编译器:如何解析函数调用和函数定义

时间:2013-09-16 04:55:58

标签: python parsing compiler-construction interpreter frontend

Upfront,我正在使用Python编写解释器,而不是编译为机器代码的实际编译器。我最近一直在浏览相当多的编译器构造指南,我理解为解析器生成令牌的基础知识,并构建一个语法树来评估算术表达式,但我不太明白如何解析带有函数调用的表达式,

之类的东西

图。 (a)中

1 + pow(1, 1)

或者当用户定义像这样的函数时如何解析行

图。 (b)中

function newFunction( someArgs ){
   ... some magic ...
}

在图(a)中,我该如何标记这个表达式?在阅读保留字“pow”之后,我应该抓住所有内容到最后的括号并将其传递给解析器吗?或者我应该将“pow”,“(”,“1”,“1”和“)”作为单独的标记包含在内并将它们添加到我的解析树中?

在Fib。 (b)在编译函数定义时,我甚至不知道从哪里开始。任何让我走向正确方向的信息都将受到赞赏。

编辑:我正在使用Backus-Naur形式语法:

  

S :: =表达式

     

表达式:: = term |术语([+ - ]术语)+

     

term :: = factor | factor([* /] factor)+

     

factor :: = number | (表达)

     

number :: = [0-9] +

2 个答案:

答案 0 :(得分:2)

希望这个问题会有一些好的方法,但我建议你做的第一件事就是提高问题的质量:

  1. 限制您的语言范围和
  2. 定义你的语法。
  3. 查看Backus–Naur Form,了解如何定义语言支持的语法。

    在第一个例子中,看一下为一些数学函数编写一个简单的解析器,以便了解它。

    <digit>   ::= "0"|"1"|...|"9"
    <integer> ::= <digit>*
    <expr>    ::= <integer> | <add> | <pow>
    <add>     ::= "add(" <expr> "," <expr> ")"
    <sub>     ::= "sub(" <expr> "," <expr> ")"
    <pow>     ::= "pow(" <expr> "," <expr> ")"
    

    从这样一个正式的语法中,你可以肯定地知道什么是有效的表达式。

    例如:add(1,2)pow(2,add(2,1))都有效,因为add(1)不是add语法需要两个表达式。

答案 1 :(得分:2)

另一张海报建议在你的语法中添加函数名称。

适用于玩具语言,但不适用于可能存在大量库以及大量用户定义函数的实用语言。

您可以通过向BNF添加函数调用来处理后者, 以一种将函数名留在语法之外的方式:

S ::= expression

expression ::= term | term ([+-] term)+

term ::= factor | factor ([*/] factor)+

factor ::= number | ( expression ) | identifier |  functioncall

functioncall ::= identifier [(]  arguments [)]

arguments ::= empty | arguments 

arguments ::= expression |  arguments [,] expression

number ::= [0-9]+

identifier ::= [a-z]+

现在你的解析器可以接收函数调用。 (左边的语法是定义函数的一种方式......但这只是我留给你添加的更多语法。)

这样做的代价是,在解析之后,某些东西决定了每个函数名称,它确切代表了它代表的代码位。您需要一个符号表来执行此操作。 这是另一个问题。