使用Jison将命令列表转换为对象数组

时间:2018-02-04 20:03:00

标签: parsing bison flex-lexer yacc jison

我正在尝试使用Jison,它是解析器生成器Bison的JS端口。我的目标是转换此输入:

foo(10)
bar()
foo(28)
baz(28)

进入这个:

[
  { func: 'foo', arg: 10 },
  { func: 'bar' },
  { func: 'foo', arg: 28 },
  { func: 'baz', arg: 28 }
]

这是我的野牛档案:

%lex

%%
[0-9]+\b                  return 'INTEGER'
\(                        return 'OPEN_PAREN'
\)                        return 'CLOSE_PAREN'
[\w]+\s*(?=\()            return 'FUNC_NAME'
\n+                       return 'LINE_END'

/lex

%%
expressions
  : expressions expression
  | expression
  ;

expression
  : LINE_END
  | e LINE_END
    {return $1}
  ;

e
  : FUNC_NAME OPEN_PAREN INTEGER CLOSE_PAREN
    {$$ = { func: $1, arg: $3 };}

  | FUNC_NAME OPEN_PAREN CLOSE_PAREN
    {$$ = { func: $1 };}
  ;

生成的生成的解析器的输出为{ func: 'foo', arg: 10 }。换句话说,它只返回第一个语句中的解析对象,而忽略其余的。

我知道我的问题与语义价值和expression的“右侧”有关,但我很遗憾。

非常感谢任何帮助!

1 个答案:

答案 0 :(得分:1)

我附加了一个符合你要求的语法。显着的变化是:

  1. LINE_END的正则表达式\n+|$也匹配输出的结尾。

  2. 我添加了start作品,其作用只是返回最终结果。

  3. 重写expression作品以生成数组。我还从{return $1}规则中删除了e LINE_END,因为这导致解析器提前返回。

  4. 修改了expressions生产以连接数组。

  5. 对于expressionexpressions制作,我在那里使用了规则的简写语法。例如,expression -> [$1]相当于expression { $$ = [$1] }

    这是语法:

    %lex
    
    %%
    [0-9]+\b                  return 'INTEGER'
    \(                        return 'OPEN_PAREN'
    \)                        return 'CLOSE_PAREN'
    [\w]+\s*(?=\()            return 'FUNC_NAME'
    \n+|$                     return 'LINE_END'
    
    /lex
    
    %%
    start:
      expressions
      { return $1 }
      ;
    
    expressions
      : expressions expression -> $1.concat($2)
      | expression
      ;
    
    expression
      : LINE_END -> []
      | e LINE_END -> [$1]
      ;
    
    e 
      : FUNC_NAME OPEN_PAREN INTEGER CLOSE_PAREN
        {$$ = { func: $1, arg: $3 };}
    
      | FUNC_NAME OPEN_PAREN CLOSE_PAREN
        {$$ = { func: $1 };}
      ;
    
    旁边:杰森不是野牛的港口。它是一个解析器生成器,其功能受到Bison 的强烈启发,但它具有Bison没有的功能,并且Jison不支持Bison的一些功能。