我正在尝试使用Java为C实现fork-merge解析器。每当我找到#if指令时,我都需要分叉解析器。例如:
int x = #if 3; #else 4; #ENDIF
上述陈述应解析如下:
首先我为#if创建一个新的解析器并在#if语句下读入所有内容,在上面的例子中,直接读取值3会抛出语法错误,在这种情况下我应该读回所有已经存在的标记读。我该怎么做?
答案 0 :(得分:0)
好吧,您可以使用任何标准解析器,并在遇到#if时复制其状态。然后一个版本沿#if的分支下移,另一个版本沿着#else的分支。 (没有#else?假装你看到#if cond lexemes #else #endif)。
如果预处理器条件不会出现在不错的地方,那么生活就会变得混乱:
void p()
{ if (x<2)
{ y =
#if cond
3; } else { x=
#else
7;
#endif
}
解析可以在每个条件子部分的末尾以完全不同的状态结束。结果是:您需要扩展预处理器条件,以便它们包含干净的语言结构。
这种方法的一个严重问题是,如果你每次看到#if时都会进行分叉,那么你最终会得到N ^ ifs的2 ^ N分叉。很容易找到包含数十个条件的C代码; 2 ^ 24 - &gt; 1600万,所以这快速失控。
所以当你点击#endif时,你需要一种方法将合并再次解析回来。这并不容易;我们用GLR解析器完成了这个,但答案非常复杂,并且在这里不容易适应。本技术论文讨论了如何为LR解析器执行此合并:http://www.lirmm.fr/~ducour/Doc-objets/ECOOP2012/PLDI/pldi/p323.pdf
还有第二个并发症:想象
#if cond1
stuff1
#else
#if cond2
stuff4
#else
stuff5
#endif
#endif
现在你需要在解析器中分叉解析器。更糟糕的是,stuff4有一个条件,它是cond1和cond2的结合,但stuff5具有cond1和cond2的条件。 ~cond2。实际上,您需要计算并保留每个解析(和生成的子树)出现的条件。您需要进行某种符号条件计算才能执行此操作,并且您需要特别处理组合条件完全错误的情况(只需跳过内容)。有趣的是,我们的GLR解决方案和上述技术论文都同意使用BDD这是一个好主意。
如果你想进行重构,你需要在有条件的情况下确定名称的含义:
#if cond1
float x;
#else
char* x;
#endif
...
x=
#if cond1
3.7
#else
"foobar"
#endif
;
这需要具有带符号的条件信息的符号表。有关如何处理此问题的详细信息,请参阅我的技术文章http://www.rcost.unisannio.it/mdipenta/papers/scam2002.pdf。
要进行重构,您需要在所有这些之上进行控制和数据流分析。
查看我的bio以获取我们试图完成所有这些工具的工具。我们认为,我们已经完成了条件解析部分。剩下的还在空中。