2

学习编程时一个很好的练习是写一个计算器。为此,我在BNF中创建了某种DSL ,并希望寻求您的帮助来改进它。使用这种迷你语言,您应该能够将值和表达式命名为名称(也就是创建变量和函数)。addmultiplyassign

先看看BNF:

<Program>     ::= <Line>(<NewLine><Line>)*
<Line>        ::= {"("}<Expression>{")"}|<Assignment>
<Assignment>  ::= <Identifier>"="<Expression>
<Identifier>  ::= <Name>{"("<Name>(","<Name>)*")"}
<Expression>  ::= <Summand>(("+"|"-")<Summand>)*
<Summand>     ::= <Factor>(("*"|"/")<Factor>)*
<Factor>      ::= <Number>|<Call>
<Call>        ::= <Name> {"("<Expression>(","<Expression>)*")"}
<Name>        ::= <Letter>(<Letter>|<Digit>)*
<Number>      ::= {"+"|"-"}(<Digit>|<DigitNoZero><Digit>+)
<Digit>       ::= "0"|<DigitNoZero>
<DigitNoZero> ::= "1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
<Letter>      ::= [a-zA-Z]
<NewLine>     ::= "\n"|"\r"|"\r\n"

如您所见,此 BNF 不处理旁边的空白NewLine。在解析开始之前,我计划NewLine从要解析的字符串中删除所有空格(当然是除了)。无论如何,这对解析器来说不是必需的。

使用现在定义的这种语言时,有 4 件事可能会导致问题,我希望您能帮助我找出合适的解决方案:

  1. 在生成此语法时,我尝试遵循自上而下的方法,但、<Expression>和之间有一个圆圈。<Summand><Factor><Call>
  2. 语法以完全相同的方式处理变量和函数。大多数编程语言都会有所作为。这里有必要区分吗?
  3. 在尝试实现 BNF 时,可能有一些我不知道的关于编程、BNF 等的事情,这会在以后杀死我。但在我开始之前,你可能会发现这一点。
  4. 可能有一些我自己找不到的简单而愚蠢的错误。在那种情况下很抱歉。我希望不再有这些错误。

使用手和脑,我可以成功解析以下测试用例:

"3"
"-3"
"3-3"
"a=3"
"a=3+b"
"a=3+b\nc=a+3"
"a(b,c)=b*c\ra(1+2,2*3)"

请帮助改进 BNF,使其可用于成功编写计算器。

编辑: 这个 BNF 真的没有完成。它不会正确处理“2+-3”(应该失败,但不会)和“2+(-3)”(应该不会失败,但会)的情况。

4

1 回答 1

2

语法以完全相同的方式处理变量和函数。大多数编程语言都会有所作为。这里有必要区分吗?

能够将函数调用的结果与局部变量或常量表达式完全相同地对待正是首先定义(数学)函数的重点。我无法想象使用允许函数但不处理的语法

1 + 1

完全一样

1 + a

或者

1 + sin(x)
于 2010-09-28T11:00:57.880 回答