我应该将换行符标记为单独的语句还是在解析器上担心这个问题?

时间:2013-02-22 17:28:08

标签: parsing compiler-construction tokenize lexer

我在PHP中构建了一个基本的标记化器,现在它解析类似于javascript的东西,尽管不需要用分号来分隔语句。

a = 1
b = a + 1
echo b

T_IDENTIFIER  a
T_EQUAL       =
T_NUMBER      1
T_IDENTIFIER  b
T_EQUAL       =
T_IDENTIFIER  a
T_NUMBER      1
T_IDENTIFIER  echo
T_IDENTIFIER  b

这是我的第一个编译器,所以我不确定我是否已准备好继续解析。我忽略了词法分析符上的换行符,因此语句之间没有分隔符,但在我的DSL换行符中可以用作分号的替代。

我的问题是,我是否应该开始担心在词法分析器上分离语句,还是应该修改我的tokenizer以包含换行符?

4 个答案:

答案 0 :(得分:1)

当你说“不需要分号来分隔陈述”时,你实际上暗示“分隔陈述是必要的。”

您可以通过在代币流中生成一些T_ENDOFINSTRUCTION来简化工作。您的解析器将使用它单独的语句。

答案 1 :(得分:1)

如果换行符是语言的一部分(例如,某个语句有时会在行边界结束),则应该将ENDOFLINE作为标记生成。这听起来像你的情况。

如果换行符总是空格,那么词法分析器应该只将它们作为空格使用。

如果换行符有时有用,有时候不行,(例如,“THEN 换行符”引入了块式THEN子句,你应该生成< em> 2 那么令牌:一个是那么,另一个是 THENnewline

我不会因为他们很容易修改而让自己担心如何在第一次尝试时使lexer正确。得到它是正确的(例如,使用上面的经验法则),然后继续编写解析器。当解析器崩溃时,如果词法分析器必须通过生成换行符或特殊标记来帮助更多,那么你就可以回过头来修改它了。

答案 2 :(得分:1)

如果您是langauge设计师,那么您可以选择。我发现将换行视为特殊笨拙的语言和有时将换行视为特殊(Scala,Haskell,Icon)的语言令人讨厌。根据语法的详细信息,可以很容易地将解析器中的语句分开,就像在Euclid和Turing中一样。例如

<Statement> ::= <Var> = <Expression>
              | echo <Expression>
              | { Block }
              | if <Expression> <Statement> else <Statement>
              | while <Expression <Statement>
<Block> ::= <Statement> <Block>
         |  <Declaration> <Block>
         |  

到目前为止,没有歧义。如果你小心其他非终结者,就不需要有任何歧义。

答案 3 :(得分:0)

我在过去几周一直在设计一种语言并手工制作词法分析器。我的语言不会将NEWLINE视为令牌,也不需要SEMICOLON来识别结尾。 表达式语法本身定义语句何时结束

这在大多数情况下都很顺利,但由于我语言中的所有语句都是表达式,因此存在一些含糊之处:

a(b)[方法调用] vs a \ n(b)[两个表达式] :我明确要求某些令牌不在NEWLINE之前,'('就是其中之一在方法调用的上下文中使用时。

4-2 [减法] vs 4 \ n -2 [两个表达式] :此外,使用与一元运算符相同的标记的二元运算符要求在它们之前没有NEWLINE。

除此之外,为了避免用户的一些错误,我明确要求如果两个表达式在同一行,则必须用SEMICOLON分隔。当然不存在含糊不清的问题,只是为了避免错字输入,例如:

c = a adn b

这会将a adn b理解为只返回 b 的单个块。