野牛和语法:重放解析堆栈

时间:2014-03-06 16:34:02

标签: parsing programming-languages bison

自从毕业学校以来,我没有以正式方式构建语言或解析器,并且忘记了当时我所知道的大部分内容。我现在有一个可能从这样的事情中受益的项目,但我不确定如何处理以下情况。

假设在我要解析的语言中有一个令牌,表示在表达式中“生成一个随机浮点数”。

exp: NUMBER
        {$$ = $1;}
    | NUMBER PLUS exp
        {$$ = $1 + $3;}
    | R PLUS exp
        {$$ = random() + $3;}
    ;

我还想要一个“list”生成运算符,它将重新评估“exp”一些次数。也许像:

listExp: NUMBER COLON exp
    {
        for (int i = 0; i < $1; i++) {
            print $3;
        }
    }
    ;

我看到的问题是,循环开始时“exp”已经减少了。如果我有输入

2 : R + 2

然后我认为随机数将在解析“exp”并添加2时生成 - 假设结果为2.0055。然后在列表表达式中我认为2.0055将被打印两次。

有没有办法在评估之前标记“exp”,然后按照列表循环计数的要求解析它多次?想法是在每次评估中获得不同的随机数。

2 个答案:

答案 0 :(得分:4)

最好的办法是在解析结束时构建AST并评估整个AST。在线评估只适用于非常简单(即“类似计算器”)的项目。

您可以为堆栈或三地址虚拟机构建代码,而不是AST。这通常更有效,特别是如果您打算经常执行代码,但AST构建起来要简单得多,执行它是一次深度优先扫描。

答案 1 :(得分:0)

根据您的语言设计,至少有5个不同的点可以将语言中的标记绑定到某个值。他们是:

  1. 预处理器(如C #define)
  2. Lexer:识别令牌
  3. Parser:识别令牌结构,输出AST
  4. 语义分析:分析AST,分配类型和转换等
  5. 代码生成:直接输出可执行代码或执行代码。
  6. 如果您有一个可以多次出现的令牌,并且您希望每次都为其分配一个不同的随机值,那么第4阶段就是这样做的地方。如果生成AST,请遍历树并分配值。如果您直接进行代码生成(或解释器),那么就这样做。