ANTLR4 javascript访问者中的ctx

时间:2020-03-16 15:35:11

标签: javascript antlr antlr4 visitor

使用ANTLR4 v4.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!'..

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());

访问者的使用似乎并不简单,this SO帖子在一定程度上有所帮助。

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

错误:

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

exception: InputMismatchException [Error]一起
我相信是因为childrennull而不是被填充。
反过来,这是由于 line 9:0 mismatched input '<EOF>' expecting {'DECLAREPROGRAM', 'PRINT'}

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

编辑17.3-添加了语法和源代码

1 个答案:

答案 0 :(得分:2)

当您调用while (my @row2 = $query3->fetchrow_array) { $query4->execute($row2[2], $row2[1], $row2[0]); print "$row2[2], $row2[1], $row2[0] \n"; } 但将输入作为输入时:

DBD::mysql::st execute failed: called with 3 bind variables when 2 are needed at worldmap2.pl line 103.
DBD::mysql::st execute failed: called with 3 bind variables when 2 are needed at worldmap2.pl line 103.

它不起作用。对于class NewsSpider(scrapy.Spider): name = 'news' def start_requests(self): page = 'https://www.coindesk.com/feed' yield scrapy.Request(url=page, callback=self.parse) def parse(self, response): links = response.xpath('//link/text()').extract() for link in links: yield scrapy.Request(url=link, callback=self.parse_contents) def parse_contents(self, response): url = response.url article_title = response.xpath('//h1/text()').extract()[0] pub_date = response.xpath('//div[@class="article-hero-datetime"]/time/@datetime').extract()[0] description = response.xpath('//meta[@name="description"]/@content').extract()[0] item = WebspiderItem() item['date'] = pub_date item['title'] = article_title item['summary'] = description item['link'] = url yield item ,解析器期望像这样的输入parser.print()。对于整个输入,您将不得不调用*************** * Hello world *************** DECLAREPROGRAM hw.. PRINT 'Hello World!'.. 。另外,明智的做法是使用EOF令牌“锚定”您的起始规则,这将迫使ANTLR消耗整个输入:

print()

如果您想解析并访问整个解析树(使用PRINT 'Hello World!'..),但只对prog()节点/上下文感兴趣,那么最好使用侦听器而不是访问器。检查此页如何使用侦听器:https://github.com/antlr/antlr4/blob/master/doc/javascript-target.md

编辑

这是侦听器的工作方式(Python演示,因为我没有正确设置JS):

progm : stmt+ EOF;

运行上面的代码时,将打印以下内容:

prog()

因此,简而言之:该侦听器接受您输入的整个解析树,但是当我们输入print解析器规则时,只能“监听”。

请注意,我将import antlr4 from playground.MygrammarLexer import MygrammarLexer from playground.MygrammarParser import MygrammarParser from playground.MygrammarListener import MygrammarListener class PrintPreprocessor(MygrammarListener): def enterPrint_(self, ctx: MygrammarParser.Print_Context): print("Entered print: `{}`".format(ctx.getText())) if __name__ == '__main__': source = """ *************** * Hello world *************** DECLAREPROGRAM hw.. PRINT 'Hello World!'.. """ lexer = MygrammarLexer(antlr4.InputStream(source)) parser = MygrammarParser(antlr4.CommonTokenStream(lexer)) antlr4.ParseTreeWalker().walk(PrintPreprocessor(), parser.progm()) 重命名为Entered print: `PRINT'Hello World!'..` 是因为print受Python目标保护。