改进数学表达式的 BNF

发布于 2024-09-25 16:15:17 字数 2039 浏览 7 评论 0 原文

学习编程时一个很好的练习就是编写计算器。为此,我在 DSL /en.wikipedia.org/wiki/Backus%E2%80%93Naur_Form" rel="nofollow">BNF 并希望寻求您的帮助来改进它。使用这种迷你语言,您应该能够为名称添加、乘法和分配值和表达式(也称为创建变量和函数)。

首先看一下 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. 我尝试遵循自上而下的方法,同时生成此语法,但 之间有一个圆圈;
  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)”(不应该失败,但确实失败)的情况。

A good exercise while learning programming, is to write a calculator. To do this, I created some kind of DSL in BNF and want to ask for your help to improve it. With this minilanguage you should be able to add, multiply and assign values and expressions to names (a.k.a. create variables and functions).

Hava a look at the BNF first:

<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"

As you can see, this BNF treats no Whitespace beside NewLine. Before the parsing begins I plan to remove all whitespace (beside NewLine of course) from the string to parse. It is not nessesary for the parser anyway.

There are 4 things, that might lead to problems when using this language as defined right now and I hope you can help me figure out appropriate solutions:

  1. I tried to follow the top-down approach, while generating this gramar, but there is a circle between <Expression>, <Summand>, <Factor> and <Call>.
  2. The gramar treats variables and functions exactly the same way. Most programming languages make a difference. Is it nessesary to differentiate here?
  3. There are maybe some things that I don't know about programming, BNF, whatever, that will kill me later, while trying to implement the BNF. But you might be able to spot that before I start.
  4. There might be simple and stupid mistakes that I could not find myself. Sorry in that case. I hope there are none of these mistakes anymore.

Using hand and brain I could successfully parse the following test cases:

"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)"

Please help to improve the BNF, that it can be used to successfully write a calculator.

edit:
This BNF is really not finished. It does not treat the cases "2+-3" (should fail, but doesn't) and "2+(-3)" (should not fail, but does) correctly.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

云之铃。 2024-10-02 16:15:17

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

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

1 + 1

完全相同的语法

1 + a

与or

1 + sin(x)

The gramar treats variables and functions exactly the same way. Most programming languages make a difference. Is it nessesary to differentiate here?

Being able to treat the result of a function invocation exactly the same as a local variable or a constant expression is precisely the point of defining (mathematical) functions in the first place. I can't imagine the use of a grammar that allowed functions but didn't treat

1 + 1

exactly the same as

1 + a

or

1 + sin(x)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文