java - 如何为算术计算java解析器编写递归while循环
问题描述
我用以下语法为算术计算解析器编写了代码
'exp' ::= 术语 | 期限 + 经验 | 期限 - exp
术语 ::= 整数字面量
而且我已经完成了仅包含整数文字的单个术语的解析器,但是,我无法实现在字符串方程中解析操作的目标。
在这个应用程序中,我试图token
通过 usingTokenizer.hasNext()
方法检查是否存在下一个存在,如果token
是类型,Token.Type.Add
则返回一个新的 Exp,其中包含当前文字项和操作以及通过该parse()
方法解析的下一个 Exp。我已经定义了各种类,例如Token(String token, Type type),Exp(Term) / Exp(Term,Op,Exp),Term(Lit),Lit(int)
Tokenizer.takeNext()
将获取下一个标记并将其从当前标记器缓冲区中删除。我根本无法从给定的方程中解析运算符。
Parsing equation: 73 + 65
73=73
Parsing equation: 10 - 4
10=10
Parsing equation: 7 + 9 + 10
7=7
Parsing equation: 5 - 1
5=5
这是我从学校讲座中获得的一般方法,它不是作业问题。任何帮助将不胜感激。
public class Token {
public enum Type {Unknown, Lit, Add, Minus, Multiply, Division};
private String _token = "";
private Type _type = Type.Unknown;
}
public enum Operation {
None (""),
Add ("+"),
Sub ("-"),
Mult ("*"),
Div ("/");
String op;
public class Exp {
Term _term = null;
Exp _exp = null;
Operation _op = null;
public Exp(Term term) {
_term = term;
_op = Operation.None;
}
public Exp(Term term, Operation op, Exp exp) {
_exp = exp;
_term = term;
_op = op;
}
public Exp parse(){
Exp term = parseTerm();
while(_tokenizer.hasNext()) {
Token token = _tokenizer.takeNext();
if(token.type() == Token.Type.Add) {
Operation op = Operation.Add;
_tokenizer.next();
Exp exp = parse();
term = new Exp(term._term,op,exp);
}
}
return term;
}
// <term> ::= <integer literal>
public Exp parseTerm(){
Exp exp = null;
String Lit = "";
while(_tokenizer.hasNext()) {
Token token = _tokenizer.takeNext();
if(token.type() == Token.Type.Lit)
Lit+=token.token();
else
parse();
}
Lit lit = new Lit(Integer.parseInt(Lit));
Term term = new Term(lit);
exp = new Exp(term);
return exp;
}
解决方案
让我们来看看这个输入73 + 65
:
你打电话parse
,哪个电话parseTerm
。parseTerm
然后循环令牌。对于第一个标记,它是一个文字,所以它被添加到Lit
(PS:变量名以大写字母开头的风格不好)。然后+
读取令牌并进入else
, 调用parse
. 现在再次parse
调用parseLit
,读取文字 for 65
。令牌流现在为空,因此parseLit
返回。parse
也返回,因为令牌流仍然是空的(请注意,parse
从未进入循环)。
parse
to返回的值parseLit
是文字表达式65
,但parseLit
从未实际使用该值。它只是调用parse
并丢弃结果。
所以现在我们回到了第一次调用parseLit
并且parse
刚刚返回。所以令牌流是空的,我们退出循环。的内容Lit
是“73”,所以这就是调用返回的内容parseLit
。现在我们回到第一次调用parse
,它只是返回结果,parseLit
因为令牌流是空的,所以永远不会进入循环。
所以这里的问题是你消耗了所有的输入而没有实际构建树来进行加法。用于执行此操作的代码(即while
循环 in parse
)永远不会运行,因为您已经在循环进入循环之前读取了所有标记,因为循环输入parseTerm
和第二次调用parse
(您丢弃其结果)。
你的语法规则term
不使用exp
,所以parseTerm
不应该调用parse
。而且该规则也不是递归的,因此parseTerm
不应包含循环。应该parseTerm
做的就是读取一个应该是文字的单个标记,然后为此返回适当的Exp
对象。
推荐阅读
- netty - 了解实例化时与临时端口相关的 NioEventLoopGroup 行为
- html - 如何使所有项目的宽度相同但尽可能小?
- javascript - 将某些内容导入/导出到 app.svelte 时,Svelte 应用程序显示空白页面
- python - X 从 1 到 N 的倍数
- excel - 将大文件拆分成多个小文件excel VBA
- django-rest-framework - NOT NULL 约束失败:api_article.author_id、Django_RestFramework Nested Serializers
- python - 如何将 discord.py 任务放入 cog 并运行它?
- macos - OMNeT++ 在 macOS 上缺少“可可”
- python - 如何使用 python 在 Web 浏览器中显示重定向 url
- typescript - TypeScript 或 ES6 版本的 lodash _.set() 用于深度对象属性分配跳过空检查