用于算术表达式的JavaCC的解析器示例

时间:2017-02-05 00:57:24

标签: parsing javacc

这是我在解析区的第一天。作为我在JavaCC中的第一个例子,代码是

SKIP:  { " " | "\t" | "\n" | "\r"                    }
TOKEN: { "(" | ")" | "+" | "*" | <NUM: (["0"-"9"])+> }

void S(): {} { E() <EOF>           }
void E(): {} { T() ("+" T())*      }
void T(): {} { F() ("*" F())*      }
void F(): {} { <NUM> | "(" E() ")" }

我想知道它为什么能处理像int +(int + int)这样的情况。通过它的算法,我认为它会将这个表达式解析为[int]&amp; [(int]&amp; [int]]为Ts并且无法解析。为什么要按预期解析?

1 个答案:

答案 0 :(得分:1)

考虑输入字符串“1+(2 + 3)”这个词作为标记序列

<NUM> "+" "(" <NUM> "+" <NUM> ")" <EOF>

该序列可以从S()导出如下。的。显示哪些令牌已被消耗。因为代币被消耗了。向右移动

         . S() 
           ~~~ expand
     ==> . E() <EOF>
           ~~~ expand
     ==> . T() ("+" T())* <EOF>
           ~~~ expand
     ==> . F() ("*" F())* ("+" T())* <EOF>
           ~~~ expand
     ==> . (<NUM> | "(" E() ")") ("*" F())* ("+" T())* <EOF>
           ~~~~~~~~~~~~~~~~~~~~~ choose first and consume
     ==> <NUM> . ("*" F())* ("+" T())* <EOF>
                 ~~~~~~~~~~ delete
     ==> <NUM> . ("+" T())* <EOF>
                 ~~~~~~~~~~ unroll and consume
     ==> <NUM> "+" . T() ("+" T())* <EOF>
                     ~~~ expand
     ==> <NUM> "+" . F() ("*" F())* ("+" T())* <EOF>
                     ~~~~
     ==> <NUM> "+" . (<NUM> | "(" E() ")") ("*" F())* ("+" T())* <EOF>
                     ~~~~~~~~~~~~~~~~~~~~~ choose second and consume
     ==> <NUM> "+" "(" . E() ")" ("*" F())* ("+" T())* <EOF>
                         ~~ expand
     ==> <NUM> "+" "(" . T() ("+" T())* ")" ("*" F())* ("+" T())* <EOF>
                         ~~~ expand
     ==> <NUM> "+" "(" . F() ("*" F())* ("+" T())* ")" ("*" F())* ("+" T())* <EOF>
                         ~~~ expand
     ==> <NUM> "+" "(" . (<NUM> | "(" E() ")") ("*" F())* ("+" T())* ")" ("*" F())* ("+" T())* <EOF>
                         ~~~~~~~~~~~~~~~~~~~~~ choose first and consume
     ==> <NUM> "+" "(" <NUM> . ("*" F())* ("+" T())* ")" ("*" F())* ("+" T())* <EOF>
                               ~~~~~~~~~~ delete
     ==> <NUM> "+" "(" <NUM> . ("+" T())* ")" ("*" F())* ("+" T())* <EOF>
                               ~~~~~~~~~~~~~~ unroll and consume
     ==> <NUM> "+" "(" <NUM> "+" . T() ("+" T())* ")" ("*" F())* ("+" T())* <EOF>
                                   ~~~ expand
     ==> <NUM> "+" "(" <NUM> "+" . F() ("*" F())* ("+" T())* ")" ("*" F())* ("+" T())* <EOF>
                                   ~~~ expand
     ==> <NUM> "+" "(" <NUM> "+" . (<NUM> | "(" E() ")") ("*" F())* ("+" T())* ")" ("*" F())* ("+" T())* <EOF>
                                   ~~~~~~~~~~~~~~~~~~~~~ choose first and consume
     ==> <NUM> "+" "(" <NUM> "+" <NUM> . ("*" F())* ("+" T())* ")" ("*" F())* ("+" T())* <EOF>
                                         ~~~~~~~~~~ delete
     ==> <NUM> "+" "(" <NUM> "+" <NUM> . ("+" T())* ")" ("*" F())* ("+" T())* <EOF>
                                         ~~~~~~~~~~ delete and consume
     ==> <NUM> "+" "(" <NUM> "+" <NUM> ")" . ("*" F())* ("+" T())* <EOF>
                                             ~~~~~~~~~~ delete
     ==> <NUM> "+" "(" <NUM> "+" <NUM> ")" . ("+" T())* <EOF>
                                             ~~~~~~~~~~ delete and consume
     ==> <NUM> "+" "(" <NUM> "+" <NUM> ")" <EOF> .

键:

  • 展开:用其定义替换非终结符。
  • 选择:用S或T替换(S | T)
  • 展开:将(S)*替换为S(S)*
  • 删除:将(S)*替换为

上面的推导是左右推导。我选择显示左右派生因为它反映了JavaCC的工作原理。