Python Antlr, почему мой код не дает ожидаемого результата? - PullRequest
0 голосов
/ 05 мая 2020

Мне нужно создать компилятор для специального языка под названием Decaf. Мне нужен файл python с именем decaf-lexer.py, который печатает список токенов, обнаруженных вашим компилятором для данного входного текстового файла. Вот моя грамматика в antlr для лексера:

grammar Decaf;

//********* LEXER ******************

fragment ALPHA : [a-zA-Z];
fragment DIGIT : [0-9];
ID : ALPHA( ALPHA | DIGIT)* ;
NUM: DIGIT(DIGIT)* ;
COMMENTS: '//' ~('\r' | '\n' )*  -> skip;
WS : (' ' | '\n')+  ->skip;

LROUND : '(';
RROUND : ')';
LCURLY : '{';
RCURLY : '}';
LSQUARE: '[' ;
RSQUARE : ']';
SEMI : ';';
CLASS: 'class';
BOOLEAN : 'boolean';
BREAK : 'break';
CALLOUT : 'callout';
CONTINUE : 'continue';
ELSE : 'else';
FALSE : 'false';
FOR : 'for';
IF : 'if';
INT : 'int';
RETURN : 'return';
TRUE : 'true';
VOID : 'void';
CHAR : ALPHA|DIGIT|' '| '#' | '$' | '&' | '.' | ':' | '?' | '@' | '\\' | '^' | '_' | '`'| '|' | '~' | '\t'| '\n' ;
COMMA: ',';
COMPARE: '==';
NEQUAL: '!=';
GREQUAL: '>=';
LSEQUAL: '<=';
LS: '<';
GR: '>';
AND: '&&';
OROR: '||';
EQUALS: '=';
PEQUAL: '+=';
MEQUAL: '-=';
PLUS: '+';
MINUS: '-';
TIMES: '*';
DIVIDE: '/';
MOD: '%';
QUOTE: '"';
SQUOTE: '\'';
EXPLANATION: '!';


Вот python код

import antlr4 as ant
from DecafLexer import DecafLexer

filein = open('example_01.decaf', 'r')
lexer = DecafLexer(ant.InputStream(filein.read()))

token = lexer.nextToken()
while token.type != -1:
    print(lexer.symbolicNames[token.type])
    token = lexer.nextToken()

Файл примера содержит только:

(x + y)

Результат:

LCURLY
COMMENTS
TIMES
COMMENTS
RCURLY

, когда это должно быть так, где я ошибаюсь ????

LROUND
ID
PLUS
ID
RROUND

Ответы [ 2 ]

1 голос
/ 05 мая 2020

Массив symbolicNames содержит имена названных правил лексера, которые вы определили в том порядке, в котором вы их определили. Однако он не содержит правил лексера, которые были неявно определены для литералов, которые вы используете в правилах парсера. Поскольку у них будет номер типа, который предшествует номерам названных правил, это означает, что вы не можете использовать token.type в качестве индекса в symbolicNames, если вы используете какие-либо неявные правила лексера в своей грамматике.

Вместо этого вы следует использовать ruleNames, который включает неявные токены. Таким образом, для любого токена с собственным именем lexer.ruleNames[token.type] будет правильно возвращать это имя, а для любых токенов, созданных из строковых литералов, он вернет строку типа T__0.

0 голосов
/ 05 мая 2020

Когда я запускаю:

lexer = DecafLexer(ant.InputStream('(x + y)'))

token = lexer.nextToken()
while token.type != -1:
    print(lexer.symbolicNames[token.type])
    token = lexer.nextToken()

, печатается следующее:

LROUND
ID
PLUS
ID
RROUND

Я предполагаю, что вы не сгенерировали новые классы анализатора и лексера из своей грамматики.

Еще одна вещь: попробуйте токенизировать ввод boolean: вы увидите, что он токенизирован как ID. Это потому, что вы определили ID перед всеми ключевыми словами (например, boolean, false, void и т. Д.). Если F ANTLR может соответствовать нескольким правилам лексического анализатора (т. Е. 2 ​​или более правил соответствуют одним и тем же символам), то «выиграет» правило, определенное первым.

Решение: переместите ID ниже всех ключевых слов:

CLASS: 'class';
BOOLEAN : 'boolean';
BREAK : 'break';
CALLOUT : 'callout';
CONTINUE : 'continue';
ELSE : 'else';
FALSE : 'false';
FOR : 'for';
IF : 'if';
INT : 'int';
RETURN : 'return';
TRUE : 'true';
VOID : 'void';

ID : ALPHA( ALPHA | DIGIT)* ;

Наконец, это правило:

CHAR : ALPHA|DIGIT|' '| '#' | '$' | '&' | '.' | ':' | '?' | '@' | '\\' | '^' | '_' | '`'| '|' | '~' | '\t'| '\n' ;

нечетное: оно может соответствовать одиночным пробелам , но вы уже указали пропускать пробелы ранее. Кроме того, вы говорите, что он соответствует одному ALPHA или DIGIT, но они соответствуют ID или NUM соответственно.

есть T_0 и T_1, созданные перед num ID ect, который сбрасывает все на двоих, есть идеи, что это такое?

Если вы определяете буквальные токены внутри правил парсера, например:

parser_rule
 : LEXER_RULE ';'
 ;

тогда это ';' будет неявно определен ANTLR, как такой T_... токен за кулисами. Но эти T_... токены не влияют на предложения из моего ответа.

...