Python Antlr 为什么我的代码不能得到预期的结果?

问题描述 投票:0回答:1

我需要为一种名为Decaf的自定义语言创建一个编译器,我需要一个名为Decaf-lexer.py的python文件。我需要一个名为decaf-lexer.py的python文件,它可以打印出编译器检测到的给定输入文本文件的标记列表。这是我在antlr中为Lexer编写的语法。

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
python compiler-construction antlr antlr4
1个回答
1
投票

数组 symbolicNames 包含了您按照定义顺序所定义的命名的词法规则的名称,但不包含您在解析规则中为字元隐式定义的词法规则。然而,它并不包含在解析器规则中隐式定义的字元的词法规则。因为这些规则的类型号会在命名规则的类型号之前,这意味着你不能使用 token.type 作为索引进入 symbolicNames 如果你在语法中使用了任何隐性词法规则。

相反,您应该使用 ruleNames,其中确实包括隐式标记。因此,对于任何一个名字为 lexer.ruleNames[token.type] 将正确地返回该名称,对于任何从字符串字面数创建的标记,它将返回一个字符串,如 T__0.


0
投票

当我运行时。

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' ;

是很奇怪的:它可以匹配单个空格字符,但你已经在前面指示跳过空格。另外,你告诉它要匹配单个 ALPHADIGIT但这些都是作为一个 IDNUM 分别。

在num ID之前有一个T_0和T_1的创建,这让所有的东西都偏离了两个,你知道这些是什么吗?

如果你在解析器规则里面定义文字标记,像这样。

parser_rule
 : LEXER_RULE ';'
 ;

那么这个 ';' 将会被ANTLR隐式地定义为像这样一个 T_... 背后的信物。但这些 T_... 不过代币对我回答的建议没有影响。

© www.soinside.com 2019 - 2024. All rights reserved.