Разбираем Cool Language с помощью antlr, не могу распечатать желаемый результат

Я пишу парсер / лексер для COOL (объектно-ориентированный язык в классе). Вы можете увидеть грамматику по следующей ссылке: (ПОСЛЕДНЯЯ СТРАНИЦА РУКОВОДСТВА)

http://theory.stanford.edu/~aiken/software/cool/cool-manual.pdf

Я использую ANTLR для написания этой программы, и со следующим вводом я хочу получить следующий результат:

Вход :

class Main inherits IO {
  main(): Object {{
    x <- 2 + 3 *4;
  }};
};

вывод :

1
2
3
11
6
16
27
18
27
27

но результат, который я получаю:

1
2
3
11
6
27
16
27
18
27

и вот мой код парсера / лексера:

// parser
grammar CA2;

program : {System.out.println("1");} (classdef';')+ ;
classdef : {System.out.println("2");} CLASS ID (INHERITS ID)? '{' (feature';')* '}' ;
feature : {System.out.println("3");} ID OPENP (formal (','formal)*)? CLOSEP ':' ID '{' expr '}' 
        | {System.out.println("4");} ID ':' ID ( POINTTOLEFT expr )? ;
formal : {System.out.println("5");} ID ':' ID ;
expr : {System.out.println("6");} ID POINTTOLEFT expr exprprime
     | {System.out.println("8");} ID OPENP ( expr (','expr)* )? CLOSEP exprprime
     | {System.out.println("9");} IF expr THEN expr ELSE expr FI exprprime
     | {System.out.println("10");} WHILE expr LOOP expr POOL exprprime 
     | {System.out.println("11");} '{' (expr';')+ '}' exprprime 
     | {System.out.println("12");} LET ID ':' ID (POINTTOLEFT expr)? (','ID ':' ID (POINTTOLEFT expr)?)* IN expr exprprime
     | {System.out.println("13");} CASE expr OF (ID POINTTORIGHT expr ';')+ ESAC exprprime
     | {System.out.println("14");} NEW ID exprprime
     | {System.out.println("15");} ISVOID expr exprprime
     /*| {System.out.println("16");} expr ADD expr
     | {System.out.println("17");} expr SUB expr
     | {System.out.println("18");} expr MULTIPLY expr
     | {System.out.println("19");} expr DIV expr
     | {System.out.println("20");} TILDA expr
     | {System.out.println("21");} expr LARGERTHAN expr
     | {System.out.println("22");} expr LARGEREQ expr
     | {System.out.println("23");} expr EQUALS expr
     | {System.out.println("24");} NOT expr
     | {System.out.println("25");} OPENP expr CLOSEP
     | {System.out.println("26");} ID
     | {System.out.println("27");} INTEGER*/
     | {System.out.println("28");} STRING exprprime | mathex exprprime ;
     /*| {System.out.println("29");} TRUE
     | {System.out.println("30");} FALSE ;*/
exprprime : {System.out.println("7");} (('@'ID)?)'.'ID OPENP (expr (','expr)*)? CLOSEP exprprime | ;
mathex : b ;
b : {System.out.println("24");} NOT b | c ;
cprime : {System.out.println("21");} LARGERTHAN d cprime 
       | {System.out.println("22");} LARGEREQ d cprime 
       | {System.out.println("23");} EQUALS d cprime | ;
c : d cprime ;
dprime : {System.out.println("16");} ADD e dprime 
       | {System.out.println("17");} SUB e dprime | ;
d : e dprime ;
eprime : {System.out.println("18");} MULTIPLY f eprime 
       | {System.out.println("19");} DIV f eprime | ;
e : f eprime ;
f : {System.out.println("20");} TILDA f | g ;
g : {System.out.println("25");} OPENP mathex CLOSEP 
  | {System.out.println("26");} ID 
  | {System.out.println("27");} INTEGER 
  | {System.out.println("29");} TRUE 
  | {System.out.println("30");} FALSE ;

//lexer
TRUE : 'true' ;
FALSE : 'false' ;
INHERITS : 'inherits' ;
CLASS : 'class' ;
IF : 'if' ;
THEN : 'then' ;
ELSE : 'else' ;
FI : 'fi' ;
WHILE : 'while' ;
LOOP : 'loop' ;
POOL : 'pool' ;
LET : 'let' ;
IN : 'in' ;
CASE : 'case' ;
OF : 'of' ;
ESAC : 'esac' ;
NEW : 'new' ;
ISVOID : 'isvoid' ;
NOT : 'not' ;
TILDA : '~' ;
WHITESPACE : [ ' '|'\r'|'\n'|'\t']+ ->skip ;
INTEGER : [0-9]+ ;
ID : ['_'a-zA-Z][a-zA-Z0-9'_']* ;
ADD : '+' ;
MULTIPLY : '*' ;
SUB : '-' ;
DIV : '/' ;
OPENP : '(' ;
CLOSEP : ')' ;
EQUALS : '=' ;
LARGERTHAN : '<' ;
LARGEREQ : '<=' ;
POINTTOLEFT : '<-' ;
POINTTORIGHT : '=>' ;
STRING : '"'(~[\r\n])*'"' ;

Это версия кода COOL грамматики в ANTLR. части, которые прокомментированы в основном коде, устранены (средства лишены двусмысленности!) и освобождены от левой рекурсии во второй части (правило математики).

может ли кто-нибудь указать, где это происходит не так и почему я не получаю желаемый результат?

заранее спасибо!


person Ashkan Kazemi    schedule 30.10.2014    source источник


Ответы (1)


За исключением действия в program, каждый из ваших println вызовов появляется непосредственно перед ссылкой на токен в грамматике. Понятно, что это означает, что они будут выполняться в том же порядке, в котором токены появляются в файле.

Ваше первое несоответствие между ожидаемыми и фактическими результатами - это перестановка строк 16 и 27. Ожидаемый результат будет иметь место только в том случае, если токен + во входных данных появится перед токеном 2 во входных данных, но ясно, что вы можете видеть, что это не так. Второе несовпадение происходит по той же причине; в частности, это связано с тем, что ожидаемый результат предполагал, что токен * появится в вашей грамматике раньше, чем токен 3.


Я заметил, что вы изначально написали леворекурсивное expr правило и включили в него встроенные действия. Следующая информация не связана с решением вашего конкретного вопроса, но ее важно понимать, если вы решите раскомментировать этот код и использовать леворекурсивную форму expr.

Рассмотрим следующее леворекурсивное правило, разрешающее простое добавление идентификаторов с добавлением двух встроенных действий.

expr
  : {a();} ID
  | {b();} expr '+' ID
  ;

Как вы, наверное, узнали, этот синтаксис не будет компилироваться с ANTLR. Мы обнаружили, что вычисление выражения {b();} в том месте, где я его здесь показал, привело к огромному (отрицательному) влиянию на производительность сгенерированного кода, поэтому мы решили не допускать этого. Результатом была бы польская префиксная форма выражения, в то время как синтаксический анализатор фактически пытается работать при вводе с использованием инфиксной записи. Решение состоит в том, чтобы вместо этого использовать инфиксную нотацию:

expr
  : {a();} ID
  | expr {b();} '+' ID
  ;

Собирая результаты вызовов a и b, вы можете преобразовать результаты в любое удобное для вас обозначение перед записью результатов. Другой вариант - перемещение встроенных действий к посетителю, который выполняется после завершения синтаксического анализа, где тривиально выполнить их в любом порядке, который вам нравится.

Дополнительная литература: Infix, Postfix и Prefix

person Sam Harwell    schedule 30.10.2014
comment
Я предполагаю, что ваш ответ на самом деле не был ответом, а скорее уловкой, позволяющей изменить результат так, как мы хотим, я прав? И вы также подразумеваете, что желаемый результат неверен, а мой результат на самом деле в порядке? - person Ashkan Kazemi; 30.10.2014
comment
@AshkanKzme Первая часть моего ответа (над hr) точно объясняет, что / почему вы получаете результат, который вы видели. Вторая часть - это просто дополнительная информация для вас, потому что я видел, как вы закомментировали леворекурсивную форму правила expr, и решил, что вы, возможно, захотите узнать, почему оно не работает. - person Sam Harwell; 30.10.2014
comment
То есть вы на самом деле не отвечаете на вопрос, а просто добавляете к нему похожую информацию. извините, не могу принять это как ответ. - person Ashkan Kazemi; 30.10.2014
comment
Вы не получите ответа лучше, чем у Сэма; он типичный эксперт по Antlr4. Вы можете игнорировать это, если хотите. - person Ira Baxter; 30.10.2014