Автор Тема: [CP][Oberon-07/11]Procedure Type call in expression.  (Прочитано 16420 раз)

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
[CP][Oberon-07/11]Procedure Type call in expression.
« : Январь 13, 2013, 07:21:03 pm »
vlad обнаружил странное - согласно синтаксису Oberon-07/11 для процедурных типов нельзя так:

MODULE Hello;
  TYPE ProcType = PROCEDURE () : INTEGER;
  VAR a : INTEGER;

  PROCEDURE A():INTEGER;
  BEGIN
    RETURN 42
  END A;

  PROCEDURE GetA() : ProcType;
  BEGIN
    RETURN A
  END GetA;

BEGIN
  a := GetA()();
END Hello.

Ключевая строчка: a:=GetA()(); То есть GetA возвращает переменную процедурного типа, и мы сразу же пытаемся её вызвать.

Я заметил еще более странное белое пятно в Oberon Report'e: там Вирт вообще нигде не говорит и не приводит примеров как эти самые процедурные переменные использовать. Ну, то есть надо ли там ^ ставить, как через них процедуры вызывать и так далее.

Но на этом странности не заканчиваются. На конфе был задан вопрос - а как там, в Component Pascal'e с этим делом?

Я покурил мануал, посмотрел грамматику, и вроде бы по грамматике, такое: GetA()() там тоже не должно быть можно. Однако ж в ББ все отлично прокатывает. То есть оно таки реально там работает. Хотя вроде как и не должно.

Попробовал в GPCP. Ругается. Вот так:
C:\Projects\gpcp-NET\NETexamples\hello>gpcp Hello.cp
  18   a := GetA()();
**** ----^ Expression not assign-compatible with destination
**** ----^ LHS type was INTEGER, RHS type was ProcType
#gpcp: <Hello> There was one error

То есть ожидаемо ругается не ожидаемым образом. При чем тут тип вообще? Там должна быть синтаксическая ошибка, до тайпчекера оно не должно было дойти вообще!

Попробовал в компиляторе akron1 (то есть это уже Oberon-07/11, модуль я написал так, что он спокойно компилируется и КП-компилятором и Оберон-компилятором). Ожидаемо ругается:
строка:  16
столбец: 8
несовместимость по присваиванию
Но тоже не ожидаемым образом - почему то и тут компиляция добралась до тайпчекера, синтаксический анализатор ошибку пропустил.

Почему это не должно работать в Обероне-07/11 на уровне синтаксиса:
Цитировать
expression  =  SimpleExpression [relation SimpleExpression].
relation  =  "=" | "#" | "<" | "<=" | ">" | ">=" | IN | IS.
SimpleExpression  =  ["+" | "-"] term {AddOperator term}.
AddOperator  =  "+" | "-" | OR.
term  =  factor {MulOperator factor}.
MulOperator  =  "*" | "/" | DIV | MOD | "&".
factor  =  number | string | NIL | TRUE | FALSE |
 set | designator [ActualParameters] | "(" expression ")" | "~" factor.

a := GetType()()

Справа у нас, очевидно, expression. Expression состоит из последовательности SimpleExpression'ов склеиваемых каким-нибудь relation'ом. У нас тут склейки очевидно нет, так что SimpleExpression будет только один (поэтому я его выделил жирным).

SimpleExpression состоит из последовательности term'ов, склевивыемых AddOperator'ами, который у нас тут очевидно также нет, так что term у нас будет один.

term состоит из factor'ов, склеиваемых MulOperator'ами, которых у нас тут тоже очевидно нет, следовательно factor у нас также один.

А factor у нас может быть много чем, но только одним чем-нибудь за раз, например десигнатором с опциональными актуальными параметрами (designator [ActualParameters]), что мы и имеем.

Внимание вопрос - каким образом сюда получилось на уровне синтаксиса прилепить еще одну пару скобочек так, что это не привело к синтаксической ошибке?

Такое ощущение складывается, что в этом месте есть баг в ББ, есть баг в GPCP и есть баг в компиляторе akorn1. Причем в двух последних баг одинаковых (на РАЗНЫХ грамматиках!)
Y = λf.(λx.f (x x)) (λx.f (x x))

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: [CP][Oberon-07/11]Procedure Type call in expression.
« Ответ #1 : Январь 13, 2013, 07:25:21 pm »
a := GetType()()

Справа у нас, ...

a:=GetA()() конечно же.
Y = λf.(λx.f (x x)) (λx.f (x x))

ddn

  • Jr. Member
  • **
  • Сообщений: 59
    • Просмотр профиля
Re: [CP][Oberon-07/11]Procedure Type call in expression.
« Ответ #2 : Январь 13, 2013, 09:57:50 pm »
Интересовался этим вопросом, и помню, что в ББ вызов процедур и функций всегда сидел в Designator:
Designator = Qualident {"." ident | "[" ExprList "]" | "^"
| "("Qualident ")" | "(" [ExprList] ")"} [ "$" ].
В секции "(" [ExprList] ")". Так что несколько вызовов подряд соответствуют синтакису.

Valery Solovey

  • Hero Member
  • *****
  • Сообщений: 509
    • Просмотр профиля
Re: [CP][Oberon-07/11]Procedure Type call in expression.
« Ответ #3 : Январь 13, 2013, 10:05:21 pm »
Не должен ругаться на синтаксическую ошибку.
Сначала синтаксический анализатор выбирает все лексемы, которые допустимы в этом месте. Потом выполняет контекстную проверку. На контекстной проверке и выскочила ошибка. Но если бы в Обероне обязательным было завершать любой оператор точкой с запятой, то при встрече второй пары скобок он бы ругнулся на неправильный синтаксис.

Я исходники не смотрел, но кажется знаю, где исправлять.

Однако, сначала проверю, ругнётся ли он на синтаксис, если я заменю у A и a тип результата с INTEGER на ProcType.

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re: [CP][Oberon-07/11]Procedure Type call in expression.
« Ответ #4 : Январь 13, 2013, 10:24:37 pm »
Не должен ругаться на синтаксическую ошибку.

Согласен. Если бы слева был процедерный тип (т.е. присваивание допустимо), то тогда да - была бы ошибка синтаксиса. Или если бы это был стэйтмент: GetA()()

Тем не менее вопрос остается - почему Вирт так сделал? Особенно коряво получается для случая POINTER TO PROCEDURE - сначала надо разыменовать в отдельную переменную, потом только можно сделать вызов.

vlad

  • Hero Member
  • *****
  • Сообщений: 1391
    • Просмотр профиля
Re: [CP][Oberon-07/11]Procedure Type call in expression.
« Ответ #5 : Январь 13, 2013, 10:35:10 pm »
Особенно коряво получается для случая POINTER TO PROCEDURE.

Хотя нет. POINTER TO PROCEDURE сам по себе не очень актуален (при наличи процедурных переменных). Но в тех редких случаях, когда он будет нужен - таки будет коряво.
Короче, ставлю на то, что Вирту оно было не нужно (в реализации его компиялтора) - и он просто не стал усложнять грамматику (как заметил ddn - в ББ это разруливается через designator).

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: [CP][Oberon-07/11]Procedure Type call in expression.
« Ответ #6 : Январь 13, 2013, 10:35:39 pm »
Интересовался этим вопросом, и помню, что в ББ вызов процедур и функций всегда сидел в Designator:
Designator = Qualident {"." ident | "[" ExprList "]" | "^"
| "("Qualident ")" | "(" [ExprList] ")"} [ "$" ].
В секции "(" [ExprList] ")". Так что несколько вызовов подряд соответствуют синтакису.
А можно на пальцах, для особо тупых? Разве секция "(" [ExprList] ")" не породит нам вложенные скобочки? Как эта грамматика породит нам GetA()() ?
Y = λf.(λx.f (x x)) (λx.f (x x))

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: [CP][Oberon-07/11]Procedure Type call in expression.
« Ответ #7 : Январь 13, 2013, 10:40:42 pm »
Не должен ругаться на синтаксическую ошибку.
Сначала синтаксический анализатор выбирает все лексемы, которые допустимы в этом месте. Потом выполняет контекстную проверку. На контекстной проверке и выскочила ошибка. Но если бы в Обероне обязательным было завершать любой оператор точкой с запятой, то при встрече второй пары скобок он бы ругнулся на неправильный синтаксис.
Стоп-стоп-стоп. Предположим у нас просто парсер, а не компилятор. На выходе он должен тупо выдать AST. Естественно никакого семантического анализатора у него там нет, и тем более тайп-чекера. Внимание вопрос - он тут найдет ошибку? И если нет, то какое дерево он нам построит?

Однако, сначала проверю, ругнётся ли он на синтаксис, если я заменю у A и a тип результата с INTEGER на ProcType.
Компилятор akorn1 ругается на рекурсивное определение типа (и я не уверен что это корректно).
Y = λf.(λx.f (x x)) (λx.f (x x))

Valery Solovey

  • Hero Member
  • *****
  • Сообщений: 509
    • Просмотр профиля
Re: [CP][Oberon-07/11]Procedure Type call in expression.
« Ответ #8 : Январь 13, 2013, 10:41:14 pm »
Ну вот:MODULE Hello;
  TYPE ProcType = PROCEDURE () : INTEGER;
  MetaProcType = PROCEDURE () : ProcType;
  VAR a : ProcType;

  PROCEDURE A():INTEGER;
  BEGIN
    RETURN 42
  END A;

  PROCEDURE GetA() : ProcType;
  BEGIN
    RETURN A
  END GetA;

  PROCEDURE GetGetA() : MetaProcType;
  BEGIN
    RETURN GetA
  END GetGetA;

BEGIN
  a := GetA()();
END Hello.
Добавил процедуру и тип. Теперь, как я и предполагал, ругается на пространство между парами скобочек.

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: [CP][Oberon-07/11]Procedure Type call in expression.
« Ответ #9 : Январь 13, 2013, 10:42:11 pm »
Интересовался этим вопросом, и помню, что в ББ вызов процедур и функций всегда сидел в Designator:
Designator = Qualident {"." ident | "[" ExprList "]" | "^"
| "("Qualident ")" | "(" [ExprList] ")"} [ "$" ].
В секции "(" [ExprList] ")". Так что несколько вызовов подряд соответствуют синтакису.
Да, на всякий случай - для тупых (меня) лучшим ответом будет показать AST для GetA()() в случае КП-грамматики.
Y = λf.(λx.f (x x)) (λx.f (x x))

X512

  • Newbie
  • *
  • Сообщений: 45
    • Просмотр профиля
Re: [CP][Oberon-07/11]Procedure Type call in expression.
« Ответ #10 : Январь 13, 2013, 10:44:37 pm »
Oberon-07 выглядит ощутимо хуже предыдущих оберонов. Зачем его использовать для не микроконтроллерного софта мне не понятно. По мне так самый лучший оберон это Component Pascal, хотя недостатков в нём тоже хватает. Например недостаточно проработаны записи, размещаемые не через NEW().

Valery Solovey

  • Hero Member
  • *****
  • Сообщений: 509
    • Просмотр профиля
Re: [CP][Oberon-07/11]Procedure Type call in expression.
« Ответ #11 : Январь 13, 2013, 10:48:07 pm »
Тем не менее вопрос остается - почему Вирт так сделал?
А это точно сделал Вирт? Я просто вопроса досконально не знаю. Может, просто в реализациях не досмотрели. Ведь не во всех языках бывает "and we need to go deeper".

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: [CP][Oberon-07/11]Procedure Type call in expression.
« Ответ #12 : Январь 13, 2013, 10:52:48 pm »
Oberon-07 выглядит ощутимо хуже предыдущих оберонов. Зачем его использовать для не микроконтроллерного софта мне не понятно. По мне так самый лучший оберон это Component Pascal, хотя недостатков в нём тоже хватает. Например недостаточно проработаны записи, размещаемые не через NEW().
Ну, КП как минимум абсолютно не портабельный, да и существенно более сложный (и для реализации и для изучения).

С другой стороны, я не вижу у Оберона-07/11 преимуществ для микроконтроллеров перед другими языками.
Y = λf.(λx.f (x x)) (λx.f (x x))

valexey_u

  • Hero Member
  • *****
  • Сообщений: 3013
    • Просмотр профиля
Re: [CP][Oberon-07/11]Procedure Type call in expression.
« Ответ #13 : Январь 13, 2013, 10:56:37 pm »
Тем не менее вопрос остается - почему Вирт так сделал?
А это точно сделал Вирт? Я просто вопроса досконально не знаю. Может, просто в реализациях не досмотрели. Ведь не во всех языках бывает "and we need to go deeper".
Вопрос появился не после того как в конкретной реализации напоролись на проблему, вопрос появился после того, как при создании своей реализации напоролись на проблему в Language report.

Проверять правильность программы опираясь на какую-либо реализацию языка в принципе нельзя, ибо нет гарантии что в реализации нет ошибок.

Я же кажется упоминал, что я, да и Влад, изучаем Oberon-07/11 преимущественно по language report'у :-) КП, кстати, тоже (когда требуется посмотреть, а как там у большого брата сделано).
Y = λf.(λx.f (x x)) (λx.f (x x))

Valery Solovey

  • Hero Member
  • *****
  • Сообщений: 509
    • Просмотр профиля
Re: [CP][Oberon-07/11]Procedure Type call in expression.
« Ответ #14 : Январь 13, 2013, 11:02:03 pm »
Стоп-стоп-стоп. Предположим у нас просто парсер, а не компилятор. На выходе он должен тупо выдать AST. Естественно никакого семантического анализатора у него там нет, и тем более тайп-чекера. Внимание вопрос - он тут найдет ошибку? И если нет, то какое дерево он нам построит?
Так или иначе в данном месте исходника выскочит ошибка. Вопрос только: на каком уровне?

Что касается гипотетического многопроходного компилятора... Ну вот прочли мы очередную лексему. Куда её девать? Добавить потомком текущему листу дерева (продолжается текущий операнд выражения)? Добавить родственником недавнего предка (встретилась операция выражения)? Добавить родственником давнего предка (следующий оператор текущей процедуры)?

То есть, по-моему, хоть какая-то контекстная проверка выполняться должна: прочли текущую лексему и изменили список ожидаемых лексем за нею.