1 Востаннє редагувалося ProgramBandera (12.05.2024 18:55:43)

Тема: Помилка в Case..Of..Else: Очікується постійний вираз!

Вітаю Незламні! Як виправити помилку "Очікується постійний вираз!" в конструкції Case..Of..Else. Ось метод в якому є конструкція Case..Of..Else:

// Метод повертає позицію оператора найвищого пріорітету в підвиразі, якщо оператор не знайдено повертає 0
Function TOperand.PositionOperator(Const PExpression: String): UInt64;
Begin

  Case True Of
    OperatorInExpression('^', PExpression): Result := PositionInExpression('^', PExpression);
    OperatorInExpression('√', PExpression): Result := PositionInExpression('√', PExpression);
    OperatorInExpression('*', PExpression): Result := PositionInExpression('*', PExpression);
    OperatorInExpression('/', PExpression): Result := PositionInExpression('/', PExpression);
    OperatorInExpression('+', PExpression): Result := PositionInExpression('+', PExpression);
    OperatorInExpression('-', PExpression):
      Begin
        For Var I := 1 To LengthExpression(PExpression) Do
          If (I = 1) And (PExpression[i] = '-') Then
            Continue                      
          Else If  (PExpression[i] = '-') Then
          Begin
            Result := I;           
            Break               
          End

      End
    Else Result := 0
  End

End;

Тут видає помилку що булева функція: OperatorInExpression() не є постійним виразом. Через If..Then..Else все працює, та код погано читабельний:

// Метод повертає позицію оператора найвищого пріорітету в підвиразі, якщо оператор не знайдено повертає 0
Function TOperand.PositionOperator(Const PExpression: String): UInt64;
Begin
  // Якщо жодного оператора не знайдено, повертаємо 0
  Result := 0;

  If OperatorInExpression('^', PExpression) Then
    Result := PositionInExpression('^', PExpression)
  Else If OperatorInExpression('√', PExpression) Then
    Result := PositionInExpression('^', PExpression)
  Else If OperatorInExpression('*', PExpression) Or OperatorInExpression('/', PExpression) Then
  Begin
                                // Від початку виразу і до кінця виразу Виконати
    For Var I := 1 To LengthExpression(PExpression) Do
                        // Якщо символ виразу є оператор '*' Або оператор '/' То
    If (PExpression[i] = '*') Or (PExpression[i] = '/') Then
    Begin
      Result := I;                    // Результату присвоюємо позицію оператора
      Break                                                  // Виходимо з циклу
    End
  End
  Else If OperatorInExpression('+', PExpression) Or OperatorInExpression('-', PExpression) Then
  Begin
                                // Від початку виразу і до кінця виразу Виконати
    For Var I := 1 To LengthExpression(PExpression) Do
    Begin
                                       // Якщо першим символом іде оператор - То
      If (I = 1) And (PExpression[i] = '-') Then
        Continue                       // переходимо до наступної ітерації циклу
                // Інакше, Якщо символ виразу є оператор '+' Або оператор '-' То
      Else
        If (PExpression[i] = '+') Or (PExpression[i] = '-') Then
        Begin
          Result := I;                // Результату присвоюємо позицію оператора
          Break                                              // Виходимо з циклу
        End
    End
  End
End;

Що в такому випадку можна зробити? Переписати через конструкцію If..Then..Else, чи можливо якось виправити помилку в Case..Of..Else?

Реалізація методів OperatorInExpression() та PositionInExpression описана нижче:

           // Метод повертає Істина якшо у виразі знайдено математичний оператор
Function TOperand.OperatorInExpression(Const POperator: WideChar; Const PExpression: String): Boolean;
Begin
  Result := False;

  For Var Op In PExpression Do
    If Op = POperator Then
    Begin
      Result := True;
      Exit
    End

End;

                   // Метод повертає першу позицію підвиразу знайденого в виразі
Function TSystemUtilities.PositionInExpression(Const PSubExpression, PExpression: String): UInt64;
Var
  J: UInt64;       // Лічильники для циклу, визначає поточну позицію в підвиразі
Begin
  Result := 0;                                  // Ініціалізуємо результат нулем

                                     // Пошук першого символу підвиразу в виразі
  For Var I := 1 To LengthExpression(PExpression) Do
  Begin
                  // Якщо символ виразу співпадає з першим символом підвиразу То
    If PExpression[i] = PSubExpression[1] Then
    Begin
                      // Порівнюємо підвираз з виразом, перевіряючи кожен символ
      J := 1;                               // Стаємо на перший символ підвиразу
      // Поки символ підвиразу <= довжини підвиразу І символи виразу та підвиразу співпадають Виконати
      While (J <= LengthExpression(PSubExpression)) And
            (I + J - 1 <= LengthExpression(PExpression)) And // Відповідний символ виразу < за довжину виразу І
            (PExpression[I + J - 1] = PSubExpression[J]) Do // Символи виразу та підвиразу співпадають Виконати
        IncreaseByOne(J);          // Переходимо до наступного символу підвиразу

      // Якщо всі символи підвиразу співпали з виразом То
      If J > LengthExpression(PSubExpression) Then
      Begin
        Result := I; // Повертаємо позицію, з якої починається підвираз у виразі
        Exit;                                              // Виходимо з функції
      End
    End
  End

End;

2 Востаннє редагувалося koala (12.05.2024 20:01:59)

Re: Помилка в Case..Of..Else: Очікується постійний вираз!

Оператор Case початково призначений для переходу на адресу з таблиці переходів, тобто

case x of
   1:...
   2:...
   3:...
end;

початково працював приблизно як goto case_table[x], де case_table - масив адрес відповідних місць у коді. Очевидно, що позиції в такому масиві не можна обчислювати під час виконання.

Але навіть якщо припустити, що case бере перший годящий результат, то все одно ваш код на case явно не еквівалентний коду на if-then-else; можливо, він працює однаково, але робить це у різний спосіб.
Крім того, ви шукаєте символи по два рази: перший - перевіряєте на наявність, другий - повертаєте позицію. Якщо ви переробите функцію, щоб вона повертала індекс як знакове число, причому якщо символ не знайдено - то 0, то можна буде цього уникнути... Ой, чекайте, та це ж стандартний Pos. Чи PosEx, якщо вам треба пропустити кілька символів на початку.

Подякували: ProgramBandera, leofun012

3

Re: Помилка в Case..Of..Else: Очікується постійний вираз!

koala написав:

.. працював приблизно як goto case_table[x], де case_table - масив адрес відповідних місць у коді. Очевидно, що позиції в такому масиві не можна обчислювати під час виконання.

Мені це не очевидно. Чому не бажано - знаю, чому не можна - дискутивно..
Все решта правильно.

4

Re: Помилка в Case..Of..Else: Очікується постійний вираз!

leofun01 написав:
koala написав:

.. працював приблизно як goto case_table[x], де case_table - масив адрес відповідних місць у коді. Очевидно, що позиції в такому масиві не можна обчислювати під час виконання.

Мені це не очевидно. Чому не бажано - знаю, чому не можна - дискутивно.

Дійсно, в принципі можна, але це створює купу проблем, на кшталт того, що треба спершу обчислити всі кейси, і незрозуміло, що робити, якщо є два однакових. Тобто виходить дуже дорога і неочевидна абстракція.

Подякували: leofun011