如何检测 origin/debug Lexer 的空值
How to detect origin/debug a Lexer's null values
我已经实现了 ANTLR4 的基本语法来构建 JavaScript 解释器
来自简单的 Javascript-esque 语言。
当我 运行 我的脚本转换代码时 (parsing/generation/transpilation) 我得到
TypeError: ctx.INT is not a function
来自转译器文件。
这是我要编译的脚本
var fs = require('fs');
var antlr4 = require('antlr4');
var buildAst = require('./build-ast');
var mylangTranspiler = require('./mylang-transpiler');
function runScript(inputText) {
var ast = buildAst(inputText);
var transpiler = new mylangTranspiler();
antlr4.tree.ParseTreeWalker.DEFAULT.walk(transpiler, ast);
// eval(transpiler.output);
fs.writeFile("./main.js", transpiler.output, function(err) {
if(err) {
return console.log(err);
}
console.log("The file was saved!");
});
}
var contents = fs.readFileSync('./tests/test.mylang', 'utf8');
console.log(contents);
runScript(contents);
module.exports = runScript;
这是捕获错误的地方
mylangTranspiler.prototype.resolveExpr = function(ctx) {
console.log(ctx);
if (ctx.INT() != null) {
return ctx.INT().getText();
} else if (ctx.ID() != null) {
return ctx.ID().getText();
} else if (ctx.STRING() != null) {
return ctx.STRING().getText().replace(/$\{([^\}]+)\}/g, '" + + "');
} else return "undefined";
}
这是我的语法文件
grammar mylang;
compilationUnit: stmt*;
stmt
: assignStmt
| invocationStmt
;
assignStmt: SET ID TO expr;
invocationStmt: ID ((expr COMMA)* expr)?;
expr: expr (MUL | DIV) expr # MulDiv
| expr (ADD | SUB) expr # AddSub
| LPAREN expr RPAREN # Parens
| ID # ID
| INT # Int
| STRING # String
;
INT: [0-9]+;
STRING : '"' .*? '"' ;
ID: [a-zA-Z_] [a-zA-Z0-9_]*;
COMMA: ',';
SAY: 'show';
SET: 'set';
TO: 'to';
MUL: 'times';
DIV: 'by';
ADD: 'add';
SUB: 'sub';
LPAREN: '(';
RPAREN: ')';
WS : [ \t\r\n]+ -> skip;
我注意到在 Lexer 文件中有一些 'null' 值出现,我怀疑这是 INT() 为 null 而它不应该为 null 的原因
词法分析器文件
mylangLexer.prototype.channelNames = [ "DEFAULT_TOKEN_CHANNEL", "HIDDEN" ];
mylangLexer.prototype.modeNames = [ "DEFAULT_MODE" ];
mylangLexer.prototype.literalNames = [ null, null, null, null, "','", "'show'",
"'set'", "'to'", "'times'", "'by'",
"'add'", "'sub'", "'('", "')'" ];
mylangLexer.prototype.symbolicNames = [ null, "INT", "STRING", "ID", "COMMA",
"SAY", "SET", "TO", "MUL", "DIV",
"ADD", "SUB", "LPAREN", "RPAREN",
"WS" ];
mylangLexer.prototype.ruleNames = [ "INT", "STRING", "ID", "COMMA", "SAY",
"SET", "TO", "MUL", "DIV", "ADD", "SUB",
"LPAREN", "RPAREN", "WS" ];
mylangLexer.prototype.grammarFileName = "mylang.g4";
我试图实现的是基本的计算器操作、变量赋值和打印到控制台,但使用不同的语法将被转换为 JavaScript。
当您使用带标签的备选方案定义解析器规则时,每个备选方案将获得自己的子类,并且只有该子类将具有与该备选方案的子规则相对应的 getter 方法。所以根据你的语法,你有以下 ExprContext
的子类:
MulDivContext
AddSubContext
ParensContext
IDContext
IntContext
StringContext
其中,只有 IntContext
有 INT()
方法。所以你不应该在 ExprContext
上调用 INT()
除非你首先确保它实际上是 IntContext
.
ANTLR-generated 听众和访问者将为每个标记的备选方案提供 enter
和 exit
或 visit
方法,因此您确保自己的方式处理 IntContext
就是定义 visitIntContext(ctx)
、visitStringContext(ctx)
等而不是 visitExprContext(ctx)
然后你就会知道 ctx
只能有对应于该备选方案的类型。
我已经实现了 ANTLR4 的基本语法来构建 JavaScript 解释器 来自简单的 Javascript-esque 语言。
当我 运行 我的脚本转换代码时 (parsing/generation/transpilation) 我得到
TypeError: ctx.INT is not a function
来自转译器文件。
这是我要编译的脚本
var fs = require('fs');
var antlr4 = require('antlr4');
var buildAst = require('./build-ast');
var mylangTranspiler = require('./mylang-transpiler');
function runScript(inputText) {
var ast = buildAst(inputText);
var transpiler = new mylangTranspiler();
antlr4.tree.ParseTreeWalker.DEFAULT.walk(transpiler, ast);
// eval(transpiler.output);
fs.writeFile("./main.js", transpiler.output, function(err) {
if(err) {
return console.log(err);
}
console.log("The file was saved!");
});
}
var contents = fs.readFileSync('./tests/test.mylang', 'utf8');
console.log(contents);
runScript(contents);
module.exports = runScript;
这是捕获错误的地方
mylangTranspiler.prototype.resolveExpr = function(ctx) {
console.log(ctx);
if (ctx.INT() != null) {
return ctx.INT().getText();
} else if (ctx.ID() != null) {
return ctx.ID().getText();
} else if (ctx.STRING() != null) {
return ctx.STRING().getText().replace(/$\{([^\}]+)\}/g, '" + + "');
} else return "undefined";
}
这是我的语法文件
grammar mylang;
compilationUnit: stmt*;
stmt
: assignStmt
| invocationStmt
;
assignStmt: SET ID TO expr;
invocationStmt: ID ((expr COMMA)* expr)?;
expr: expr (MUL | DIV) expr # MulDiv
| expr (ADD | SUB) expr # AddSub
| LPAREN expr RPAREN # Parens
| ID # ID
| INT # Int
| STRING # String
;
INT: [0-9]+;
STRING : '"' .*? '"' ;
ID: [a-zA-Z_] [a-zA-Z0-9_]*;
COMMA: ',';
SAY: 'show';
SET: 'set';
TO: 'to';
MUL: 'times';
DIV: 'by';
ADD: 'add';
SUB: 'sub';
LPAREN: '(';
RPAREN: ')';
WS : [ \t\r\n]+ -> skip;
我注意到在 Lexer 文件中有一些 'null' 值出现,我怀疑这是 INT() 为 null 而它不应该为 null 的原因
词法分析器文件
mylangLexer.prototype.channelNames = [ "DEFAULT_TOKEN_CHANNEL", "HIDDEN" ];
mylangLexer.prototype.modeNames = [ "DEFAULT_MODE" ];
mylangLexer.prototype.literalNames = [ null, null, null, null, "','", "'show'",
"'set'", "'to'", "'times'", "'by'",
"'add'", "'sub'", "'('", "')'" ];
mylangLexer.prototype.symbolicNames = [ null, "INT", "STRING", "ID", "COMMA",
"SAY", "SET", "TO", "MUL", "DIV",
"ADD", "SUB", "LPAREN", "RPAREN",
"WS" ];
mylangLexer.prototype.ruleNames = [ "INT", "STRING", "ID", "COMMA", "SAY",
"SET", "TO", "MUL", "DIV", "ADD", "SUB",
"LPAREN", "RPAREN", "WS" ];
mylangLexer.prototype.grammarFileName = "mylang.g4";
我试图实现的是基本的计算器操作、变量赋值和打印到控制台,但使用不同的语法将被转换为 JavaScript。
当您使用带标签的备选方案定义解析器规则时,每个备选方案将获得自己的子类,并且只有该子类将具有与该备选方案的子规则相对应的 getter 方法。所以根据你的语法,你有以下 ExprContext
的子类:
MulDivContext
AddSubContext
ParensContext
IDContext
IntContext
StringContext
其中,只有 IntContext
有 INT()
方法。所以你不应该在 ExprContext
上调用 INT()
除非你首先确保它实际上是 IntContext
.
ANTLR-generated 听众和访问者将为每个标记的备选方案提供 enter
和 exit
或 visit
方法,因此您确保自己的方式处理 IntContext
就是定义 visitIntContext(ctx)
、visitStringContext(ctx)
等而不是 visitExprContext(ctx)
然后你就会知道 ctx
只能有对应于该备选方案的类型。