Antlr 生产产生一堆单元素数组
Antlr production producing a bunch of single element arrays
我的语法没有问题,但我在树中有一堆元素是单元素数组,我不太明白为什么。我尝试阅读有关访问者的信息,但我很确定“问题”出在语法上,也许是它的冗长。这里有什么东西跳出来吗?或者也许我只是错误地访问了事物。在下面的示例中,我不对 visitFnArgs 或 visitArgs 做出反应,而只是对 visitFunctionCall 做出反应。函数参数和语句之类的东西有时似乎被包裹在单个元素数组中。
grammar Txl;
root: program;
// High level language
program: stmt (NEWLINE stmt)* NEWLINE? EOF # Statement
;
stmt: require # Condition
| entry # CreateEntry
| assignment # Assign
;
require: REQUIRE valueExpression;
entry: (CREDIT | DEBIT) journal valueExpression (IF valueExpression)? (LPAREN 'id:' valueExpression RPAREN)?;
assignment: IDENT ASSIGN valueExpression;
journal: IDENT COLON IDENT;
valueExpression: expr # Expression;
expr: expr (MULT | DIV) expr # MulDiv
| expr (PLUS | MINUS) expr # AddSub
| expr MOD expr # Mod
| expr POW expr # Pow
| MINUS expr # Negative
| expr AND expr # And
| expr OR expr # Or
| NOT expr # Not
| expr EQ expr # Equality
| expr NEQ expr # Inequality
| expr (LTE | GTE) expr # CmpEqual
| expr (LT | GT) expr # Cmp
| expr QUESTION expr COLON expr # Ternary
| LPAREN expr RPAREN # Parens
| NUMBER # NumberLiteral
| IDENT LPAREN args RPAREN # FunctionCall
| IDENT # Identifier
| STRING_LITERAL # StringLiteral
;
fnArg: expr | journal;
args: (fnArg (',' fnArg)*)?;
// Reserved words
CREDIT: 'credit';
DEBIT: 'debit';
IF: 'if';
REQUIRE: 'require';
// Operators
MULT: '*';
DIV: '/';
MINUS: '-';
PLUS: '+';
POW: '^';
MOD: '%';
LPAREN: '(';
RPAREN: ')';
LBRACE: '[';
RBRACE: ']';
COMMA: ',';
EQ: '==';
NEQ: '!=';
GTE: '>=';
LTE: '<=';
GT: '>';
LT: '<';
ASSIGN: '=';
QUESTION: '?';
COLON: ':';
AND: 'and';
OR: 'or';
NOT: 'not';
HASH: '#';
NEWLINE : [\r\n];
WS: [ \t] + -> skip;
// Entities
NUMBER: ('0' .. '9') + ('.' ('0' .. '9') +)?;
IDENT: [a-zA-Z]+[0-9a-zA-Z]*;
EXTID: [a-zA-Z0-9-]+;
STRING_LITERAL : '"' (~('"' | '\' | '\r' | '\n') | '\' ('"' | '\'))* '"';
这次输入:
require balance(assets:cash) + balance(assets:earnings) > AMT
生成以下单元素数组:
SINGLE ELEMENT INSTRUCTION MathOperation (>)
SINGLE ELEMENT INSTRUCTION JournalReference { identifier: 'assets:cash' }
SINGLE ELEMENT INSTRUCTION JournalReference { identifier: 'assets:earnings' }
我想知道我的部分问题是否是我没有正确访问事物。这是我的数学访问者:
visitMath(ctx) {
const visited = this.visitChildren(ctx);
return new MathOperation(
visited[0],
ctx.getChild(1).getText(),
visited[2],
);
}
但我认为问题出在包含数学运算的部分,我认为是 visitRequire:
visitRequire(ctx) {
return new Condition(this.visitExpression(ctx.getChild(1)));
}
或者可能在 visitValueExpression 或 visitCondition 中,它们在我的访问者中没有被覆盖。
非常简短的回答:单元素数组没有错。如果只有一个实例 可以 多次存在,那么它必须是一个数组(或列表),并且该列表将只有一个项目,如果是这样的话有很多。
Antlr 不会将单个项目“解包”为不在数组中。 (这仅在无类型语言或允许联合类型的语言中有效,并且使用起来会很痛苦,因为您总是必须检查您是否有“事物”或“事物”列表)
任何时候“相同类型的事物”可以 在匹配规则时存在不止一次,ANTLR 将把它作为该类型的 Array/List 提供。
示例:
journal: IDENT COLON IDENT;
有 2 个 IDENT
标记,因此可以通过上下文访问这些类型的列表
(在 Java 中,我不确定您使用的是哪种语言)。
public List<TerminalNode> IDENT() { return getTokens(TxlParser.IDENT); }
你的两个例子是“JournalReference”,所以这将解释如何获得一个列表(如果你使用 ctx.IDENT()
或 ctx.getChild(n)
方法)。
如果我将日志规则更改为:
journal: j1=IDENT COLON j2=IDENT;
我已经为每个 IDENT
命名,所以我为它们获得了单独的访问器(除了 IDENT() 访问器 returns 一个列表:
public static class JournalContext extends ParserRuleContext {
public Token j1;
public Token j2;
public TerminalNode COLON() { return getToken(TxlParser.COLON, 0); }
public List<TerminalNode> IDENT() { return getTokens(TxlParser.IDENT); }
通过标签,您可以使用 cox.j1
或 cox.j2
来获取单个令牌。 (当然,您会根据您的用例为它们命名)。
因为 FunctionCall
替代 expr
规则使用 args
规则
args: (fnArg (',' fnArg)*)?;
并且该规则可以有多个 fnArg,在上下文中它必然是 fnArg
s 的列表:
public static class ArgsContext extends ParserRuleContext {
public List<FnArgContext> fnArg() {
return getRuleContexts(FnArgContext.class);
}
你真的没有多少可以做的(或者应该想做的是不在列表中,可以有一个或多个。
由于您提供的代码没有显示您正在编写输出的位置,因此很难比这更具体。
您的 visitMath(cox)
示例也有点令人困惑,因为 math
不是您语法中的规则,因此它不会存在于访问者界面中。
我建议您仔细查看为您生成的 *Context
类。他们将提供比 getChild(n)
更易于使用和阅读的实用方法。 getChild(n)
是晦涩的,因为你必须返回参考规则并努力计算规则成员以确定要获得哪个 child,而且它也非常脆弱,因为 n
将随着对语法的任何修改而改变。 (维护者或未来的您会喜欢使用实用方法。)
我的语法没有问题,但我在树中有一堆元素是单元素数组,我不太明白为什么。我尝试阅读有关访问者的信息,但我很确定“问题”出在语法上,也许是它的冗长。这里有什么东西跳出来吗?或者也许我只是错误地访问了事物。在下面的示例中,我不对 visitFnArgs 或 visitArgs 做出反应,而只是对 visitFunctionCall 做出反应。函数参数和语句之类的东西有时似乎被包裹在单个元素数组中。
grammar Txl;
root: program;
// High level language
program: stmt (NEWLINE stmt)* NEWLINE? EOF # Statement
;
stmt: require # Condition
| entry # CreateEntry
| assignment # Assign
;
require: REQUIRE valueExpression;
entry: (CREDIT | DEBIT) journal valueExpression (IF valueExpression)? (LPAREN 'id:' valueExpression RPAREN)?;
assignment: IDENT ASSIGN valueExpression;
journal: IDENT COLON IDENT;
valueExpression: expr # Expression;
expr: expr (MULT | DIV) expr # MulDiv
| expr (PLUS | MINUS) expr # AddSub
| expr MOD expr # Mod
| expr POW expr # Pow
| MINUS expr # Negative
| expr AND expr # And
| expr OR expr # Or
| NOT expr # Not
| expr EQ expr # Equality
| expr NEQ expr # Inequality
| expr (LTE | GTE) expr # CmpEqual
| expr (LT | GT) expr # Cmp
| expr QUESTION expr COLON expr # Ternary
| LPAREN expr RPAREN # Parens
| NUMBER # NumberLiteral
| IDENT LPAREN args RPAREN # FunctionCall
| IDENT # Identifier
| STRING_LITERAL # StringLiteral
;
fnArg: expr | journal;
args: (fnArg (',' fnArg)*)?;
// Reserved words
CREDIT: 'credit';
DEBIT: 'debit';
IF: 'if';
REQUIRE: 'require';
// Operators
MULT: '*';
DIV: '/';
MINUS: '-';
PLUS: '+';
POW: '^';
MOD: '%';
LPAREN: '(';
RPAREN: ')';
LBRACE: '[';
RBRACE: ']';
COMMA: ',';
EQ: '==';
NEQ: '!=';
GTE: '>=';
LTE: '<=';
GT: '>';
LT: '<';
ASSIGN: '=';
QUESTION: '?';
COLON: ':';
AND: 'and';
OR: 'or';
NOT: 'not';
HASH: '#';
NEWLINE : [\r\n];
WS: [ \t] + -> skip;
// Entities
NUMBER: ('0' .. '9') + ('.' ('0' .. '9') +)?;
IDENT: [a-zA-Z]+[0-9a-zA-Z]*;
EXTID: [a-zA-Z0-9-]+;
STRING_LITERAL : '"' (~('"' | '\' | '\r' | '\n') | '\' ('"' | '\'))* '"';
这次输入:
require balance(assets:cash) + balance(assets:earnings) > AMT
生成以下单元素数组:
SINGLE ELEMENT INSTRUCTION MathOperation (>)
SINGLE ELEMENT INSTRUCTION JournalReference { identifier: 'assets:cash' }
SINGLE ELEMENT INSTRUCTION JournalReference { identifier: 'assets:earnings' }
我想知道我的部分问题是否是我没有正确访问事物。这是我的数学访问者:
visitMath(ctx) {
const visited = this.visitChildren(ctx);
return new MathOperation(
visited[0],
ctx.getChild(1).getText(),
visited[2],
);
}
但我认为问题出在包含数学运算的部分,我认为是 visitRequire:
visitRequire(ctx) {
return new Condition(this.visitExpression(ctx.getChild(1)));
}
或者可能在 visitValueExpression 或 visitCondition 中,它们在我的访问者中没有被覆盖。
非常简短的回答:单元素数组没有错。如果只有一个实例 可以 多次存在,那么它必须是一个数组(或列表),并且该列表将只有一个项目,如果是这样的话有很多。
Antlr 不会将单个项目“解包”为不在数组中。 (这仅在无类型语言或允许联合类型的语言中有效,并且使用起来会很痛苦,因为您总是必须检查您是否有“事物”或“事物”列表)
任何时候“相同类型的事物”可以 在匹配规则时存在不止一次,ANTLR 将把它作为该类型的 Array/List 提供。
示例:
journal: IDENT COLON IDENT;
有 2 个 IDENT
标记,因此可以通过上下文访问这些类型的列表
(在 Java 中,我不确定您使用的是哪种语言)。
public List<TerminalNode> IDENT() { return getTokens(TxlParser.IDENT); }
你的两个例子是“JournalReference”,所以这将解释如何获得一个列表(如果你使用 ctx.IDENT()
或 ctx.getChild(n)
方法)。
如果我将日志规则更改为:
journal: j1=IDENT COLON j2=IDENT;
我已经为每个 IDENT
命名,所以我为它们获得了单独的访问器(除了 IDENT() 访问器 returns 一个列表:
public static class JournalContext extends ParserRuleContext {
public Token j1;
public Token j2;
public TerminalNode COLON() { return getToken(TxlParser.COLON, 0); }
public List<TerminalNode> IDENT() { return getTokens(TxlParser.IDENT); }
通过标签,您可以使用 cox.j1
或 cox.j2
来获取单个令牌。 (当然,您会根据您的用例为它们命名)。
因为 FunctionCall
替代 expr
规则使用 args
规则
args: (fnArg (',' fnArg)*)?;
并且该规则可以有多个 fnArg,在上下文中它必然是 fnArg
s 的列表:
public static class ArgsContext extends ParserRuleContext {
public List<FnArgContext> fnArg() {
return getRuleContexts(FnArgContext.class);
}
你真的没有多少可以做的(或者应该想做的是不在列表中,可以有一个或多个。
由于您提供的代码没有显示您正在编写输出的位置,因此很难比这更具体。
您的 visitMath(cox)
示例也有点令人困惑,因为 math
不是您语法中的规则,因此它不会存在于访问者界面中。
我建议您仔细查看为您生成的 *Context
类。他们将提供比 getChild(n)
更易于使用和阅读的实用方法。 getChild(n)
是晦涩的,因为你必须返回参考规则并努力计算规则成员以确定要获得哪个 child,而且它也非常脆弱,因为 n
将随着对语法的任何修改而改变。 (维护者或未来的您会喜欢使用实用方法。)