【问题标题】:Save variable value for future use on peg.js保存变量值以供将来在 peg.js 上使用
【发布时间】:2017-04-19 01:12:37
【问题描述】:

我正在使用 Peg.js 实现一个关系代数到 SQL 的转换器。我实现了几乎所有的操作,但我没有实现分配运算符,其中关系被转换为 SQL 并保存在变量中以供将来使用。 (例如:A

由于原始代码有 200 多行,我将发布一个简单的示例来解释我认为捕获此规则的想法。

解析器代码:

{
    var variables = [];
    console.log(variables);
    function save(chave, value, rest){
            console.log("save", chave, value);
            variables[chave] = value;
            return rest;
    }

    function get(chave){
        console.log("get", chave);
        return variables[chave];
    }

}


start 
  = _ id:Identificador _ "=" _ val:Integer _ [\n]* _ rest:start
   {save(id,val);}
  / _ val:Integer _ {return val;}
  / _ id:Identificador _ {console.log(id, variables[id]); return get(id);}


Identificador "identificador"
  = [a-zA-Z]+ {return text();}
Integer "integer"
  = [0-9]+ { return parseInt(text(), 10); }

_ "whitespace"
  = [ \t\r]*

输入示例:

A = 23
B = 45
A

在我的解析器开始时,我创建了一个数组来存储要保存的值,可以通过变量名访问。

在我的第一条规则中,我声明了每个标识符,后跟赋值运算符(在我的示例中是等号),然后是要保存的值(在示例中是整数),然后是换行,然后对于其余的文本,将在数组中保存,将标识符存储为键及其值,并处理查询的其余部分。

在第一条规则的最后一行,我声明任何只包含字母标识符的行都将被其存储的值替换。在示例中,解析器应返回值 23,这是分配给变量 A 的值。

但是解析器返回undefined。我检查了 Web 控制台,发现执行顺序不正确。

Console after running the parser

有没有办法设置确切的执行顺序?我希望解析器在处理其余文本之前保存找到的值。

【问题讨论】:

  • 不应该variables 使用对象而不是数组吗?
  • @JoshVoigts,是不是要把variables的类型改成object,每次添加都会增加一个新属性?
  • 这似乎是有道理的,因为在任何上下文中都只能有 一个 具有该名称的变量。
  • 亲爱的@JoshVoigts,我将变量的类型更改为对象,但它的工作方式相同。但是知道 PEG 在执行函数之前会解释所有标记,导致在保存值之前访问键的值,所以我决定在解析器遇到这种情况时返回一个对象。 = _ id:Identifier _ "←" _ save:UnionRelation __ newline _ rest:start {return {"type" : "attrib", id : id, value: save, rest: rest};} 之后,我想创建一个后处理器来完成剩下的翻译工作。

标签: javascript parsing peg pegjs


【解决方案1】:

我不确定如何使 peg 反转评估顺序,但您可以将所有表达式放入堆栈,然后以相反的顺序评估它们。试试这个:

{
    var stack = [];
    var result = null;

    var variables = {};
    console.log(variables);
    function save(chave, value, rest){
            console.log("save", chave, value);
            stack.push(()=>{variables[chave] = value});
            return rest;
    }

    function get(chave){
        console.log("get", chave);
        stack.push(()=>{result = variables[chave]});
    }

    function evalStack() {
        for (var i = stack.length - 1; 0 <= i; i--) {
            stack[i]()
        }
        return result;
    }
}


start
  = expr
    {return evalStack();}

expr
  = _ id:Identificador _ "=" _ val:Integer _ [\n]* _ rest:expr
   {save(id,val);}
  / _ val:Integer _ {return val;}
  / _ id:Identificador _ {console.log(id, variables[id]); return get(id);}


Identificador "identificador"
  = [a-zA-Z]+ {return text();}
Integer "integer"
  = [0-9]+ { return parseInt(text(), 10); }

_ "whitespace"
  = [ \t\r]*

【讨论】:

  • 明白了,您的代码使用新的 ECMAScript lambda 表示法存储指令读取顺序(从最后一行到第一行)。然后,只需从数组的最后一个索引运行到第一个索引,到达正确的顺序。一个出色而优雅的解决方案。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-01
  • 1970-01-01
  • 2011-11-07
  • 2016-01-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多