1

我在 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 中,换行符可以用作分号的替代方案。

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

4

4 回答 4

1

当您说“不需要分号来分隔语句”时,实际上是在暗示“分隔语句需要换行符”。

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

于 2013-02-22T17:37:39.460 回答
1

如果换行符是语言的一部分(例如,语句有时以行边界结束),您可能应该生成 ENDOFLINE 作为标记。这种听起来像你的情况。

如果换行符总是空格,词法分析器应该把它们当作空格来吃。

如果换行符有时有用,有时没用(例如,“THEN newline ”引入了块式 THEN 子句,您可能应该生成2 个THEN 标记:一个是THEN,一个是THENnewline

我不会因为担心如何在第一次尝试时就正确使用词法分析器而自杀,因为它们很容易修改。把它弄好(例如,使用上面的经验法则),然后继续编写你的解析器。随着解析器的冻结,很明显词法分析器是否必须通过生成换行符或特殊标记来提供更多帮助,然后您可以返回并相应地对其进行修改。

于 2013-02-22T17:38:28.400 回答
1

如果您是语言设计师,那么选择权在您手中。我发现将换行符视为特别尴尬的语言和有时将换行符视为特殊的语言(Scala、Haskell、Icon)令人讨厌。根据您的语法细节,在解析器中分离语句可能很容易,就像在 Euclid 和 Turing 中所做的那样。例如

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

到目前为止没有任何歧义。如果您注意其他非终结符,则不必有任何歧义。

于 2013-02-22T18:10:04.430 回答
0

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

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

a(b) [方法调用] vs a \n (b) [两个表达式]:我明确要求NEWLINE前面没有一些标记,在方法调用的上下文中使用'('是其中之一。

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

除此之外,为了避免用户的一些错误,我明确要求如果两个表达式在同一行,它们必须用分号分隔。当然,这里没有歧义,只是为了避免错别字未被发现,例如:

c = a adn b

这可以理解为仅返回 ba adn b的单个块。

于 2013-02-22T18:43:21.810 回答