【发布时间】:2016-04-11 20:56:42
【问题描述】:
TL;DR VERSION:是否有支持以下内容的解析器生成器:当某些规则被缩减时(我假设为 LALR(1) 解析器),则不执行缩减,但解析器后退并用不同的代码替换输入使用此规则中的值并解析该代码。如果需要,请重复。所以如果代码是“i++”并且规则是“expr POST_INCR”,我可以做更多或更少:
expr POST_INCR -> "(tmp = expr; expr = expr + 1; tmp)"
所以基本上是使用宏重写代码?
长版:
我编写了另一种简单的解释语言(为简单起见,用 Java 编写)。它工作正常,但它提出了一些问题。简介很长,但很简单,有助于清楚地展示我的问题(我认为)。
我有“while”循环。这很简单,因为:
WHILE LPARE boolean_expression RPAREN statement
我或多或少会生成以下内容:
new WhileNode(boolean_expression, statement);
这会创建新节点,稍后访问该节点时,会为我的虚拟机生成代码。但我也有以下几点:
FOR LPAREN for_init_expr SEMICOLON boolean_expression SEMICOLON for_post_expr RPAREN statement
这是 Java 或 C 中已知的“for 循环”。根据上述规则,我或多或少地创建了以下内容:
new ListNode(
for_init_expr,
new WhileNode(
boolean_expression,
new ListNode(
statement,
new ListNode(for_post_expr, null))))
这当然是简单的转换,来自:
for (for_init ; boolean_expression ; for_post_expr)
statement
到:
for_init
while (boolean_expression) {
statement
for_post_expr;
}
一切都很好,花花公子,但以下情况变得棘手:
FOR LPAREN var_decl COLON expression RPAREN statement
如果众所周知并且喜欢的话:
for (int x : new int[] { 1, 2 })
print(x);
我不会发布生成 AST 的代码,因为基本的 for 循环已经有点长了,而且我们在这里得到的结果更糟。这种构造等于:
int[] tmp = new int[] { 1, 2 };
for (int it = 0 ; it < tmp.length; it = it + 1) {
int x = tmp[it];
print(x);
}
由于我没有使用类型,我只是假设“表达式”(所以右侧,在冒号之后)是我可以迭代的东西(并且数组不可迭代),我调用一个函数的结果这个“表达式”返回 Iterable 的实例。所以,其实我重写的代码并没有上面那么简单,多多少少是这样的:
Iterator it = makeIterable(new int[] { 1, 2 });
while (it.hasNext()) {
int x = it.next();
print(x);
}
看起来并没有那么糟糕,但请注意 AST 会为此生成三个函数调用和 while 循环。为了向您展示这是什么混乱,我发布了我现在拥有的内容:
113 | FOR LPAREN var_decl_name.v PIPE simple_value_field_or_call.o RPAREN statement.s
114 {: Symbol sv = ext(_symbol_v, _symbol_o);
115 String autoVarName = generateAutoVariableName();
116 Node iter = new StatementEndNode(sv, "",
117 new BinNode(sv, CMD.SET, "=",
118 new VarDeclNode(sv, autoVarName),
119 new CallNode(sv, "()",
120 new BinNode(sv, CMD.DOT, ".",
121 new MkIterNode(sv, o),
122 new PushConstNode(sv, "iterator")))));
123 Node varinit = new StatementEndNode(sv, "",
124 new BinNode(sv, CMD.SET, "=",
125 v,
126 new PushConstNode(sv, "null")));
127 Node hasnext = new CallNode(sv, "()",
128 new BinNode(sv, CMD.DOT, ".",
129 new VarNode(sv, autoVarName),
130 new PushConstNode(sv, "hasNext")));
131 Node vargennext = new StatementEndNode(sv, "",
132 new BinNode(sv, CMD.SET, "=",
133 new VarNode(sv, v.name),
134 new CallNode(sv, "()",
135 new BinNode(sv, CMD.DOT, ".",
136 new VarNode(sv, autoVarName),
137 new PushConstNode(sv, "next")))));
138 return new ListNode(sv, "",
139 new ListNode(sv, "",
140 new ListNode(sv, "",
141 iter
142 ),
143 varinit
144 ),
145 new WhileNode(sv, "while",
146 hasnext,
147 new ListNode(sv, "",
148 new ListNode(sv, "",
149 vargennext
150 ),
151 s)));
回答您的问题:是的,我为这段代码感到羞耻。
问题:是否有解析器生成器让我做点什么,即给定规则:
FOR LPAREN var_decl COLON expr RPAREN statement
告诉解析器重写它,就好像它是别的东西一样。我想这需要某种 LISP 的宏机制(由于基本上没有任何语法,这在 lisp 中很容易),可能类似于:
FOR LPAREN var_decl COLON expr RPAREN statement =
{ with [ x = generateAutoName(); ]
emit [ "Iterator $x = makeIterable($expr).iterator();"
"while (${x}.hasNext()) {"
"$var_decl = ${x}.next();"
"$statement"
"}"
]
}
我不知道这是否是一个众所周知的问题,我什至不知道要寻找什么 - 我发现的最相似的问题是这个问题:Any software for pattern-matching and -rewriting source code? 但它不在任何地方接近我需要的,因为它应该作为一个单独的步骤而不是在编译期间工作,所以它不符合条件。
我们将不胜感激。
【问题讨论】: