antlr visitor:有效查找保留字
antlr visitor: lookup of reserved words efficiently
我正在学习 Antlr。在这一点上,作为我学习过程的一部分,我正在编写一种基于堆栈的小语言——想想 PostScript 或 Forth。一种 RPN 语言。例如:
10 20 多
这会将 10 和 20 压入堆栈,然后执行乘法运算,弹出两个值,将它们相乘,然后压入 200。我正在使用访问者模式。我发现自己写了一些有点疯狂的代码。必须有更好的方法。
这是我的 WaveParser.g4 文件的一部分:
any_operator:
value_operator |
stack_operator |
logic_operator |
math_operator |
flow_control_operator;
value_operator:
BIND | DEF
;
stack_operator:
DUP |
EXCH |
POP |
COPY |
ROLL |
INDEX |
CLEAR |
COUNT
;
BIND 只是 bind
关键字等。所以我的访问者有这个方法:
antlrcpp::Any WaveVisitor::visitAny_operator(Parser::Any_operatorContext *ctx);
现在这里是我正在编写的非常难看的代码的地方,这导致了问题。
Value::Operator op = Value::Operator::NO_OP;
WaveParser::Value_operatorContext * valueOp = ctx->value_operator();
WaveParser::Stack_operatorContext * stackOp = ctx->stack_operator();
WaveParser::Logic_operatorContext * logicOp = ctx->logic_operator();
WaveParser::Math_operatorContext * mathOp = ctx->math_operator();
WaveParser::Flow_control_operatorContext * flowOp = ctx->flow_control_operator();
if (valueOp) {
if (valueOp->BIND()) {
op = Value::Operator::BIND;
}
else if (valueOp->DEF()) {
op = Value::Operator::DEF;
}
}
else if (stackOp) {
if (stackOp->DUP()) {
op = Value::Operator::DUP;
}
...
}
...
我支持大约 50 个运算符,我要用这一系列的 if 语句来确定这是哪个运算符,这太疯狂了。必须有更好的方法来做到这一点。我在上下文中找不到映射到我可以在哈希图中使用的内容的字段 table.
我不知道是否应该让我的每个操作员都有一个单独的规则,并在我的访问者中使用相应的方法,或者我还缺少什么。
有没有更好的方法?
使用 ANTLR,标记规则的组件以及高级替代项通常非常有帮助。
如果解析器规则的一部分只能是单一类型的事物,通常默认访问器就可以了。但是,如果您有多个备选方案,这些备选方案本质上是“同一事物”的备选方案,或者您可能多次在解析器规则中引用相同的子规则并希望区分它们,那么给它们命名会非常方便。 (一旦您开始这样做并看到对 Context classes 的影响,它们提供价值的地方就会变得非常明显。)
此外,当规则有多个顶级备选方案时,给每个备选方案贴上标签会非常方便。这将导致 ANTLR 为每个备选方案生成一个单独的上下文 class,而不是将每个备选方案中的所有内容转储到单个 class.
(为了获得有效的编译而编造一些东西)
grammar WaveParser
;
any_operator
: value_operator # val_op
| stack_operator # stack_op
| logic_operator # logic_op
| math_operator # math_op
| flow_control_operator # flow_op
;
value_operator: op = ( BIND | DEF);
stack_operator
: op = (
DUP
| EXCH
| POP
| COPY
| ROLL
| INDEX
| CLEAR
| COUNT
)
;
logic_operator: op = (AND | OR);
math_operator: op = (ADD | SUB);
flow_control_operator: op = (FLOW1 | FLOW2);
AND: 'and';
OR: 'or';
ADD: '+';
SUB: '-';
FLOW1: '>>';
FLOW2: '<<';
BIND: 'bind';
DEF: 'def';
DUP: 'dup';
EXCH: 'exch';
POP: 'pop';
COPY: 'copy';
ROLL: 'roll';
INDEX: 'index';
CLEAR: 'clear';
COUNT: 'count';
我正在学习 Antlr。在这一点上,作为我学习过程的一部分,我正在编写一种基于堆栈的小语言——想想 PostScript 或 Forth。一种 RPN 语言。例如:
10 20 多
这会将 10 和 20 压入堆栈,然后执行乘法运算,弹出两个值,将它们相乘,然后压入 200。我正在使用访问者模式。我发现自己写了一些有点疯狂的代码。必须有更好的方法。
这是我的 WaveParser.g4 文件的一部分:
any_operator:
value_operator |
stack_operator |
logic_operator |
math_operator |
flow_control_operator;
value_operator:
BIND | DEF
;
stack_operator:
DUP |
EXCH |
POP |
COPY |
ROLL |
INDEX |
CLEAR |
COUNT
;
BIND 只是 bind
关键字等。所以我的访问者有这个方法:
antlrcpp::Any WaveVisitor::visitAny_operator(Parser::Any_operatorContext *ctx);
现在这里是我正在编写的非常难看的代码的地方,这导致了问题。
Value::Operator op = Value::Operator::NO_OP;
WaveParser::Value_operatorContext * valueOp = ctx->value_operator();
WaveParser::Stack_operatorContext * stackOp = ctx->stack_operator();
WaveParser::Logic_operatorContext * logicOp = ctx->logic_operator();
WaveParser::Math_operatorContext * mathOp = ctx->math_operator();
WaveParser::Flow_control_operatorContext * flowOp = ctx->flow_control_operator();
if (valueOp) {
if (valueOp->BIND()) {
op = Value::Operator::BIND;
}
else if (valueOp->DEF()) {
op = Value::Operator::DEF;
}
}
else if (stackOp) {
if (stackOp->DUP()) {
op = Value::Operator::DUP;
}
...
}
...
我支持大约 50 个运算符,我要用这一系列的 if 语句来确定这是哪个运算符,这太疯狂了。必须有更好的方法来做到这一点。我在上下文中找不到映射到我可以在哈希图中使用的内容的字段 table.
我不知道是否应该让我的每个操作员都有一个单独的规则,并在我的访问者中使用相应的方法,或者我还缺少什么。
有没有更好的方法?
使用 ANTLR,标记规则的组件以及高级替代项通常非常有帮助。
如果解析器规则的一部分只能是单一类型的事物,通常默认访问器就可以了。但是,如果您有多个备选方案,这些备选方案本质上是“同一事物”的备选方案,或者您可能多次在解析器规则中引用相同的子规则并希望区分它们,那么给它们命名会非常方便。 (一旦您开始这样做并看到对 Context classes 的影响,它们提供价值的地方就会变得非常明显。)
此外,当规则有多个顶级备选方案时,给每个备选方案贴上标签会非常方便。这将导致 ANTLR 为每个备选方案生成一个单独的上下文 class,而不是将每个备选方案中的所有内容转储到单个 class.
(为了获得有效的编译而编造一些东西)
grammar WaveParser
;
any_operator
: value_operator # val_op
| stack_operator # stack_op
| logic_operator # logic_op
| math_operator # math_op
| flow_control_operator # flow_op
;
value_operator: op = ( BIND | DEF);
stack_operator
: op = (
DUP
| EXCH
| POP
| COPY
| ROLL
| INDEX
| CLEAR
| COUNT
)
;
logic_operator: op = (AND | OR);
math_operator: op = (ADD | SUB);
flow_control_operator: op = (FLOW1 | FLOW2);
AND: 'and';
OR: 'or';
ADD: '+';
SUB: '-';
FLOW1: '>>';
FLOW2: '<<';
BIND: 'bind';
DEF: 'def';
DUP: 'dup';
EXCH: 'exch';
POP: 'pop';
COPY: 'copy';
ROLL: 'roll';
INDEX: 'index';
CLEAR: 'clear';
COUNT: 'count';