我现在正在为学校做作业,专注于为简单的指令集构建一个标记器和解析器。该指令集使用我们必须输出给用户的EBNF语法。举个简单的例子,假设这个指令集代码如下所示:
set 0, 2 * (4 + 20)
halt
EBNF语法是这样给出的:
<Program> -> <Statement> { <Statement> }
<Statement> -> <Set> | 'halt'
<Set> -> set ('write'|<Expr>), ('read'|<Expr>)
<Expr> -> <Term> {(+|-) <Term>}
<Term> -> <Factor> {(*|/|%) <Factor>}
<Factor> -> <Number> | 'D['<Expr>']' | '('<Expr>')'
<Number> -> 0 | (1...9){0...9}
在这种情况下,<...>
是我输出给用户的内容,{...}
表示选择0或更多,(...)
表示选择1或更多,&#39; ...& #39;是一个字符串文字。
因此,在这种情况下,运行程序时,正确的输出应如下所示:
Program
Statement
Set // set
Expr // 0
Term // 0 is a term
Factor // 0 is a factor
Number // 0 is finally a number
Expr // go to the next string, "2*(4+2)"
Term // start with the number 2
Factor // 2 is a factor
Number // 2 is a number
Factor // after 2, we have a * so after that is a factor
Expr // the factor leads to a (...) which leads to an expr
Term // the expr leads to a term 4
Factor // 4 is a factor
Number // 4 is returned as a number
Term // we have a + so the next string (20) is a term
Factor // 20 is a factor
Number // return 20 as a number
Statement // halt is a statement, end
我已经构建了赋值的tokenizer部分,因此运行上面的指令集会产生一个std::vector<std::string>
,看起来像这样(每个新字符串用新行分隔):
set
0
2*(4+20)
halt
现在解析器就是我被卡住的地方。我首先将每个字符串推入std::queue
,检查字符串,解析它,然后从队列中弹出它。我已经拥有它,以便set
语句推送字符串&#34; Set&#34;在另一个std::vector<std::string>
中,我可以稍后打印出来。
我还有一个函数parse_expression(std::string& str)
来解析我的表达式。我遇到的真正麻烦在于如何正确解析2 * (4 + 20)
部分。
我的老师告诉我要通过字符串逐个字符,检查它是否是一个数字(我知道该怎么做),或者它是否匹配&#39; +&#39;,&#39; - &#39;,&#39; /&#39;,&#39; *&#39;,&#39;%&#39;角色,或者如果下一个角色是&#39; D&#39;然后我应该解析另一个表达。
我对如何尝试这一点感到困惑。如果我逐个字符,我可以获得第一个数字,直到我点击非数字字符,然后只需Term
后跟Factor
后跟Number
。但是,我怎么能回到那个原始角色并继续前进到下一个角色。几乎就像,我如何回到原来的水平,以便我能够正确地确定是否需要创建另一个Expr,或者我是否应该再做一个术语。
我意识到这是一个长期的,令人困惑的问题,但我会感谢任何正确方向的推动,是否明显是我做错了,或者它是否是解析器实际工作的方式。< / p>