如何使用解析器表达式语法处理先前声明的常量?

时间:2015-03-15 05:09:15

标签: parsing rust peg

在玩具DSL中说我有以下内容:

int foo(int bar = 0);

使用rust-peg之类的工具,我可以定义一些简单的解析器表达式语法(PEG)规则来匹配它(假设适当的结构FnProto和&#39; Arg&#39;):< / p>

function -> FnProto
  = t:type " " n:name "(" v:arglist ");"
  { FnProto { return_type:t, name:n, args:v } }

arglist -> Vec<Arg>
  = arg ** ","

arg -> Arg
  = t:type " " n:name " = " z:integer { Arg { typename:t, name:n, value:z } }

type -> String
  = "int" { match_str.to_string() }

name -> String
  = [a-zA-Z_]+[a-zA-Z0-9_] { match_str.to_string() }

integer -> i64
  = "-"? [0-9]+ { match_str.parse().unwrap() }

在实践中,这些简单的规则是不够的,但它们将有助于说明我的观点。

现在考虑以下情况,其中bar的默认值是先前在同一文件中定义的常量:

int BAZ = 0xDEADBEEF;

int foo(int bar = BAZ);

现在解析函数的规则不仅需要接受整数文字作为默认参数值,还需要接受任何先前声明的常量。

我可以做一次传递来解析常量并在第二次传递中替换相应的值,但是我真的必须求助于两次传递吗?有什么方法可以引用规则中以前解析过的数据吗?

1 个答案:

答案 0 :(得分:4)

你很困惑&#34;解析&#34; (对有效程序的识别,可能包括捕获它的表示[例如,作为AST])以及语义分析和/或执行。

您的解析器应该定义什么是 legal ,在语法上用语法来说。没有更少,仅此而已。您可能能够编写一些语义无意义的程序,解析器不会抱怨这些程序。

解析完文本后,您现在需要&#34;其他通行证&#34;解析数据(不是源文本)以构建经典编译器结构(如符号表),并检查符号的所有使用是否有效。要做那些其他的通行证,你可以说是重新解析文本,但你已经通过假设完成了一次。这里的标准解决方案是让第一个解析构建一个抽象语法树(AST),表示程序的基本细节。那些&#34;其他通行证&#34;通过走AST而不是再次解析源文本来进行操作。

这是经典的,并在标准编译器类和书籍中讲授。如果您认真考虑构建编程语言,则需要此背景知识。

相关问题