正如标题所说:当从解析树传播值时,当我在那里调用self.visitChildren(ctx)时,根节点返回None。我可以看到其他节点向上传播值,但根节点是唯一接收None的节点。
我使用的是ANTLR 4.10.1和Python antlr4-python3-runtime 4.10。
当我输入393939393和CTRL-D时,它打印以下内容:
Number: 393939393
Atom: {'type': 'number', 'value': '393939393'}
SExpr: None
None
我尝试对S-Expression解析器进行以下轻微修改,然后显示我的访问者脚本:
/*
Port to Antlr4 by Tom Everett
*/
grammar sexpr;
sexpr
/* : item* EOF */
: item EOF
;
item
: atom
| list_
/* | LPAREN item DOT item RPAREN */
;
list_
: LPAREN item* RPAREN
;
atom
: string
| symbol
| number
/* | DOT */
;
string: STRING ;
symbol: SYMBOL ;
number: NUMBER ;
STRING
: '"' ('\' . | ~ ('\' | '"'))* '"'
;
WHITESPACE
: (' ' | 'n' | 't' | 'r')+ -> skip
;
NUMBER
: ('+' | '-')? (DIGIT)+ ('.' (DIGIT)+)?
;
SYMBOL
: SYMBOL_START (SYMBOL_START | DIGIT)*
;
LPAREN
: '('
;
RPAREN
: ')'
;
DOT
: '.'
;
fragment SYMBOL_START
: ('a' .. 'z')
| ('A' .. 'Z')
| '+'
| '-'
| '*'
| '/'
| '.'
;
fragment DIGIT
: ('0' .. '9')
;
Python 3 ANTLR访问者代码
#!/usr/bin/python3
import sys
from antlr4 import *
from sexprLexer import sexprLexer
from sexprParser import sexprParser
from sexprVisitor import sexprVisitor
class SExprVisitor(sexprVisitor):
def visitSexpr(self, ctx):
r = self.visitChildren(ctx)
print("SExpr: %s" % r)
return r
def visitItem(self, ctx):
r = self.visitChildren(ctx)
return r
def visitAtom(self, ctx):
r = self.visitChildren(ctx)
print("Atom: %s" % r)
return r
def visitString(self, ctx):
print("String: %s" % ctx.getText())
return {'type':'string', 'value':ctx.getText()}
def visitNumber(self, ctx):
print("Number: %s" % ctx.getText())
return {'type':'number', 'value':ctx.getText()}
def visitSymbol(self, ctx):
print("Symbol: %s" % ctx.getText())
return {'type':'symbol', 'value':ctx.getText()}
def visitor_main(argv):
input_stream = StdinStream()
lexer = sexprLexer(input_stream)
stream = CommonTokenStream(lexer)
parser = sexprParser(stream)
tree = parser.sexpr()
visitor = SExprVisitor()
output = visitor.visit(tree)
print(output)
def main(argv):
visitor_main(argv)
if __name__ == '__main__':
main(sys.argv)
根节点以EOF
令牌结束,这是访问者调用visitChildren
后返回的内容。如果您在访问者:
def visitTerminal(self, ctx):
# The `EOF` will now return this instead of `None`
return '???'
您将看到???
由visitSexpr
返回。
要修复它,只需调用visitSexpr
中的item
:
def visitSexpr(self, ctx):
r = self.visitChildren(ctx.item())
print("SExpr: %s" % r)
return r
您可以使用[...]
而不是旧的v3语法'?' .. '?'
:
grammar sexpr;
sexpr
/* : item* EOF */
: item EOF
;
item
: atom
| list_
/* | LPAREN item DOT item RPAREN */
;
list_
: LPAREN item* RPAREN
;
atom
: string
| symbol
| number
/* | DOT */
;
string: STRING ;
symbol: SYMBOL ;
number: NUMBER ;
STRING
: '"' ('\' . | ~[\"])* '"'
;
WHITESPACE
: [ trn]+ -> skip
;
NUMBER
:[+-]? (DIGIT)+ ('.' (DIGIT)+)?
;
SYMBOL
: SYMBOL_START (SYMBOL_START | DIGIT)*
;
LPAREN
: '('
;
RPAREN
: ')'
;
DOT
: '.'
;
fragment SYMBOL_START
: [a-zA-Z+-*/.]
;
fragment DIGIT
: [0-9]
;
编辑
我不明白你对[…]中紧凑语法的评论
我的意思是旧的v3语法'a' .. 'z'
可以在v4中写成[a-z]
,使其更紧凑。
如果我使用item*而不是item遍历项目的最佳方法是什么?…
你在评论中添加的内容可能会起作用。您可以稍微更改语法,以创建其他规则使用的items : item*;
规则。您也可以使用替代标签,这样您就不需要额外的规则,如string
,symbol
和number
。
快速演示:
/*
Port to Antlr4 by Tom Everett
*/
grammar sexpr;
sexpr
: items EOF
;
items
: item*
;
item
: atom #item_atom
| list_ #item_list
;
list_
: LPAREN items RPAREN
;
atom
: STRING #atom_string
| SYMBOL #atom_symbol
| NUMBER #atom_number
;
STRING
: '"' ('\' . | ~[\"])* '"'
;
WHITESPACE
: [ trn]+ -> skip
;
NUMBER
:[+-]? (DIGIT)+ ('.' (DIGIT)+)?
;
SYMBOL
: SYMBOL_START (SYMBOL_START | DIGIT)*
;
LPAREN
: '('
;
RPAREN
: ')'
;
DOT
: '.'
;
fragment SYMBOL_START
: [a-zA-Z+-*/.]
;
fragment DIGIT
: [0-9]
;
如果你现在运行:
import sys
from antlr4 import *
from sexprLexer import sexprLexer
from sexprParser import sexprParser
from sexprVisitor import sexprVisitor
class SExprVisitor(sexprVisitor):
def visitSexpr(self, ctx):
return self.visit(ctx.items())
def visitItems(self, ctx):
items = []
for item in ctx.item():
items.append(self.visit(item))
return items
def visitItem_atom(self, ctx):
return self.visit(ctx.atom())
def visitItem_list(self, ctx):
return self.visit(ctx.list_())
def visitList_(self, ctx):
return self.visit(ctx.items())
def visitAtom_string(self, ctx):
return {'type': 'string', 'value': ctx.getText()}
def visitAtom_number(self, ctx):
return {'type': 'number', 'value': ctx.getText()}
def visitAtom_symbol(self, ctx):
return {'type': 'symbol', 'value': ctx.getText()}
def visitor_main(argv):
lexer = sexprLexer(InputStream('("Q" 42 /7)'))
stream = CommonTokenStream(lexer)
parser = sexprParser(stream)
tree = parser.sexpr()
visitor = SExprVisitor()
output = visitor.visit(tree)
print(output)
def main(argv):
visitor_main(argv)
if __name__ == '__main__':
main(sys.argv)
打印以下内容:
[[{'type': 'string', 'value': '"Q"'}, {'type': 'number', 'value': '42'}, {'type': 'symbol', 'value': '/7'}]]