ANTLR4 javascript访问者中的ctx

ANTLR4 javascript访问者中的ctx,javascript,antlr,antlr4,visitor,Javascript,Antlr,Antlr4,Visitor,使用ANTLR4v4.8 我正在编写transpiler,探索ANTLR(带访问者的javascript目标)的使用 语法->lex/parse很好,我现在坐在解析树上 语法 grammar Mygrammar; /* * parser rules */ progm : stmt+; stmt : progdecl | print ; progdecl : PROGDECLKW ID '..'; print : WRITEKW STRLIT '..'; /* * lex

使用ANTLR4v4.8

我正在编写transpiler,探索ANTLR(带访问者的javascript目标)的使用

语法->lex/parse很好,我现在坐在解析树上

语法

grammar Mygrammar;

/*
 * parser rules
 */

progm   : stmt+;

stmt
: progdecl
| print
;

progdecl : PROGDECLKW ID '..';
print    : WRITEKW STRLIT '..';

/*
 * lexer rules
 */

PROGDECLKW  : 'DECLAREPROGRAM';
WRITEKW     : 'PRINT';

// Literal
STRLIT             : '\'' .*? '\'' ;

// Identifier 
ID              : [a-zA-Z0-9]+;

// skip
LINE_COMMENT    : '*' .*? '\n' -> skip;
TERMINATOR      : [\r\n]+ -> skip;
WS              : [ \t\n\r]+ -> skip;
hw.mg

***************
* Hello world
***************

DECLAREPROGRAM  hw..

PRINT 'Hello World!'..

PrintContext {
  parentCtx: null,
  invokingState: -1,
  ruleIndex: 3,
  children: null,
  start: CommonToken {
    source: [ [MygrammarLexer], [FileStream] ],
    type: -1,
    channel: 0,
    start: 217,

index.js

...
const myVisitor = require('./src/myVisitor').myVisitor;

const input = './src_sample/hw.mg';
const chars = new antlr4.FileStream(input);
...
parser.buildParseTrees = true;

const myVisit = new myVisitor();
myVisit.visitPrint(parser.print());
访问者的使用似乎并不简单,而post在一定程度上起到了帮助作用

关于上下文的使用。当我点击每个节点时,是否有一种跟踪ctx的好方法?
使用
myVisit.visit(树)
作为起始上下文是可以的。当我开始访问每个节点时,使用非根上下文
myVisit.visitPrint(parser.print())
抛出错误

错误:

***************
* Hello world
***************

DECLAREPROGRAM  hw..

PRINT 'Hello World!'..

PrintContext {
  parentCtx: null,
  invokingState: -1,
  ruleIndex: 3,
  children: null,
  start: CommonToken {
    source: [ [MygrammarLexer], [FileStream] ],
    type: -1,
    channel: 0,
    start: 217,

与异常一起出现:输入不匹配异常[错误]
我相信这是因为
children
null
而不是被填充。
这反过来又是由于
第9:0行不匹配的输入'',应为{'DECLAREPROGRAM','PRINT'}

问题:
以上是传递上下文的唯一方法还是我做错了? 如果使用正确,那么我倾向于将此报告为bug


编辑17.3-在调用
parser.print()
时添加语法和源代码,但向其提供输入:

***************
* Hello world
***************

DECLAREPROGRAM  hw..

PRINT 'Hello World!'..
这是行不通的。对于
print()。对于整个输入,您必须调用
prog()
。此外,明智的做法是使用EOF令牌“锚定”您的启动规则,这将强制ANTLR使用整个输入:

progm : stmt+ EOF;
如果您想解析并访问整个解析树(使用
prog()
),但只对
print
节点/上下文感兴趣,那么最好使用侦听器而不是访问者。检查此页面如何使用侦听器:

编辑 以下是侦听器的工作原理(由于我没有正确设置JS,因此是Python演示):

导入antlr4
从游乐场.MygrammarLexer导入MygrammarLexer
从游乐场.MygrammarParser导入MygrammarParser
从playway.MygrammarListener导入MygrammarListener
类打印预处理器(MygrammarListener):
def enterPrint_u(self,ctx:MygrammarParser.Print_u上下文):
打印(“输入的打印:`{}`.”格式(ctx.getText())
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
来源=”“
***************
*你好,世界
***************
申报程序hw。。
打印“你好,世界!”。。
"""
lexer=MygrammarLexer(antlr4.InputStream(源))
parser=MygrammarParser(antlr4.CommonTokenStream(lexer))
antlr4.ParseTreeWalker().walk(printproprocessor(),parser.progm())
运行上述代码时,将打印以下内容:

Entered print: `PRINT'Hello World!'..`
因此,简而言之:这个侦听器接受您输入的整个解析树,但当我们输入
print
解析器规则时,只“侦听”


请注意,我将
print
重命名为
print
,因为
print
在Python目标中受保护。

您的语法似乎无法解析输入。请编辑您的问题并添加语法和输入,以便其他人可以复制。@BartKiers语法添加,谢谢。尽管语法是这个错误的根源,parser.print()是否正确仍然是个问题。我的观点是,如果解析器产生错误,访问者将不会按照您期望的方式操作。此外,如果无法访问正在解析的源代码和使用的语法,就无法对您的问题进行评论/建议。我仍然看不出您试图解析的输入是什么(您的
'./src_sample/hw.mg'
文件的内容)@BartKiers我明白了。也许我会推迟我自己对ctx的强调,直到这个错误得到解决,以保持简单。再次感谢您的关注。我的想法是:当你不能使用个人访问者方法时,为什么要生成个人访问者方法
visitPrint
visitProgdecl
等等?我与java示例形成对比,java示例提供了传递上下文的好方法
visitPrintExpr(LabeledExprParser.PrintExprContext ctx)
(来自ANTLR参考书的示例),在java示例中,这种方法工作得很好。
progm:stmt+EOF是,同意。我已经做了这个更新(并不是说它对上面的vis-a-vis有帮助)。“我与java示例形成对比……”:java访问者可以做什么,JS目标也可以。对于Java目标,您试图实现的目标也是不可能的:对于Java,您也不能解析整个inout文件,然后对其调用
print()
。“我的想法:为什么要生成单个访问者方法…”因为您可以解析输入的不同部分,然后相应地调用这些访问者方法。但是,您不能向它提供由
progm
解析的内容,然后调用
print()
(不考虑目标语言)。我查看了多个java示例,看不到任何单独的解析运行正在进行。也许你可以指一个?为了能够有选择地解析每个访问者方法的代码部分,我需要对其进行预解析,并事先知道需要为哪个方法解析哪个部分?我不能相信这一点。