问题描述
我为下面的表达式创建了 EBNF
<expression> ::= <or_operand> [ "or" <or_operand> ]
<or_operand> ::= <and_operand> [ "and" <and_operand> ]
<and_operand> ::= <equality_operand> [ ( "=" | "!=" ) <equality_operand> ]
<equality_operand> ::= <simple_expression> [ <relational_operator> <simple_expression> ]
<relational_op> ::= "<" | ">" | "<=" | ">="
<simple_expression> ::= <term> [ ( "+" | "-" ) <term> ]
<term> ::= <factor> [ ( "*" | "/" ) <factor> ]
<factor> ::= <literal>
| "(" <expression> ")"
| "not" <factor>
| ( "+" | "-" ) <factor>
<literal> ::= <boolean_literal> | <number>
<boolean_literal> ::= "true" | "false"
<number> ::= <digit> [ <digit> ]
<digit> ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
我的问题出在因子部分
<factor> ::= <literal>
| "(" <expression> ")"
| "not" <factor>
| ( "+" | "-" ) <factor>
您可以看到我包含了三个一元运算符 not
、-
和 +
。它们适用于特定类型,例如 not
仅适用于布尔值,而 +
/-
仅适用于数字。
我不知道如何处理 not
与 +
/-
混合使用的情况,例如 not +7
、- not true
等。有什么办法可以修改语法,使 not
永远不能与 +
/-
混用吗?
够了吗?
<factor> ::= <literal>
| "(" <expression> ")"
| ( "not" | ( "+" | "-" ) ) <factor>
或者也许解析器的工作是解决这个问题?
解决方法
这很容易解决。你有两种不同风格的表达式,每种风格都有自己的语法,所以你不要混合它们,并保持它们的语法规则分开。
布尔表达式只能出现在某些地方,例如赋值或某种选择语句。数值表达式只能出现在比较或赋值中。这不是在语义层面处理的事情,如果看很多语言的语法,就是这样解决的。
所以你有数字表达式:
<simple_expression> ::= <term> [ ( "+" | "-" ) <term> ]
<term> ::= <factor> [ ( "*" | "/" ) <factor> ]
<factor> ::= <number>
| "(" <expression> ")"
| ( "+" | "-" ) <factor>
<number> ::= <digit> [ <digit> ]
<digit> ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
这现在是自包含的。我们现在可以将其构建为布尔表达式:
<boolean_expression> ::= "not" <boolean_expression>
| <logical_expression>
<logical_expression> ::= <or_operand> [ "or" <or_operand> ]
<or_operand> ::= <and_operand> [ "and" <and_operand> ]
<and_operand> ::= <equality_operand> [ ( "=" | "!=" ) <equality_operand> ]
<equality_operand> ::= <simple_expression> [ <relational_operator> <simple_expression> ]
| <boolean_literal>
<relational_op> ::= "<" | ">" | "<=" | ">="
<boolean_literal> ::= "true" | "false"
请注意,我允许布尔文字的相等比较,但是如果您不想允许这样做,您可以更改规则以仅允许它们用于和操作数。
现在我们可以在另一个规则中使用这些,例如赋值:
<assignment> ::= <variable> ":=" ( <simple_expression> | <boolean_expression> )
一切都完成了。