我是 antlr 的新手,在正確決議源代碼時遇到了一些問題,這是我的語法:
compilationUnit
: (assignment | declarationList | definitionList)* EOF
;
block
: LC RC
;
assignment: typeSpecifier? IDENTIFIER '=' expression ';';
expression
: INTEGER
;
statementList
:
;
declarationList
: declaration
| declarationList declaration
;
declaration
: functionDeclaration SEMICOLON
;
functionDeclaration
: typeSpecifier? functionName functionArgs
;
definitionList
: functionDefinition
;
functionDefinition: functionDeclaration block;
functionName: IDENTIFIER;
functionArgs: LP RP;
typeSpecifier: VOID | INT;
TYPE_SPECIFIER
: VOID
| INT
;
IDENTIFIER: [a-zA-Z_][a-zA-Z0-9_]*;
INTEGER: [1-9][0-9]*;
STRING_LITERAL: '"' ~('"')* '"';
VOID: 'void';
INT: 'int';
STAR: '*';
LP: '(';
RP: ')';
LC: '{';
RC: '}';
LSQRB: '[';
RSQRB: ']';
SEMICOLON: ';';
WS: [ \t\r\n] -> skip;
NEWLINE
: ( '\r' '\n'?
| '\n'
)
-> skip
;
BLOCK_COMMENT
: '/*' .*? '*/'
-> skip
;
LINE_COMMENT
: '//' ~[\r\n]*
-> skip
;
問題是 typeSpecifier 沒有正確匹配,除非我將其更改為詞法分析器規則,所以如果我輸入如下內容:
void b();
int a = 1;
它回傳:
line 1:0 extraneous input 'void' expecting {<EOF>, IDENTIFIER, 'void', 'int'}
line 2:0 extraneous input 'int' expecting {<EOF>, IDENTIFIER, 'void', 'int'}
但是如果我將 typeSpecifier 重命名為 TYPE_SPECIFIER 它會決議它而沒有錯誤,問題是分配int a = 1時我無法區分節點和終端節點,識別符號也有同樣的問題,所以它會回傳:
'int' = <class 'antlr4.tree.Tree.TerminalNodeImpl'>
'a' = <class 'antlr4.tree.Tree.TerminalNodeImpl'>
'=' = <class 'antlr4.tree.Tree.TerminalNodeImpl'>
'1' = <class 'core.CParser.CParser.ExpressionContext'>
';' = <class 'antlr4.tree.Tree.TerminalNodeImpl'>
我希望它回傳更像:
'int' = <class 'antlr4.tree.Tree.TypeSpecifier'>
'a' = <class 'antlr4.tree.Tree.Identifier'>
'=' = <class 'antlr4.tree.Tree.AssignEq'> #or something like that
'1' = <class 'core.CParser.CParser.ExpressionContext'>
';' = <class 'antlr4.tree.Tree.SemiCol'>
這是我的 python 訪問者代碼:
from core.CParser import CParser
from core.CListener import CListener
from io import FileIO
from antlr4.tree.Tree import TerminalNodeImpl
class Listener(CListener):
def __init__(self, output):
self.output: FileIO = output
def add_newline(self):
self.output.write('\n')
def enterDeclaration(self, ctx: CParser.DeclarationContext):
...
def enterFunctionDeclaration(self,
ctx: CParser.FunctionDeclarationContext):
for child in ctx.getChildren():
if isinstance(child, TerminalNodeImpl):
self.output.write(child.getText() ' ')
if isinstance(child, CParser.FunctionNameContext):
self.output.write(child.getText())
if isinstance(child, CParser.FunctionArgsContext):
self.output.write(child.getText())
self.output.write(';')
self.add_newline()
def enterAssignment(self, ctx: CParser.AssignmentContext):
for child in ctx.getChildren():
if isinstance(child, TerminalNodeImpl):
self.output.write(child.getText() ' ')
if isinstance(child, CParser.ExpressionContext):
self.output.write(child.getText())
self.add_newline()
def enterBlock(self, ctx: CParser.BlockContext):
print(ctx.getText())
先感謝您 :)
uj5u.com熱心網友回復:
你有以下兩個:
typeSpecifier: VOID | INT;
TYPE_SPECIFIER
: VOID
| INT
;
然而,您從未TYPE_SPECIFIER在任何決議器規則中使用過該令牌。(并且TYPE_SPECIFIERLexer 規則將是分配的標記型別;您將永遠不會看到具有此規則的VOIDorINT標記。您實際上是在使它們成為片段規則。)
洗掉TYPE_SPECIFIERLexer 規則(你一開始就有正確的想法。)
但是,您需要將規則移到IDENTIFIERLexer 規則中的任何關鍵字下方(在 Lexer 規則的“領帶”中,ANTLR 將使用第一個定義的規則,因此您永遠不會看到關鍵字規則,因為您的關鍵字也會匹配,更通用的識別符號規則)。
——
EOF此外,定義一個以確保決議所有輸入的開始規則是一個非常好的主意。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/515438.html
上一篇:如何使用帶有haxeflixel的xml檔案創建影片?
下一篇:消除運算式轉換語法中的歧義
