JavaCC - 将数学表达式解析为类结构
我正在使用这个语法来计算数学表达式:
// Konfiguration (JavaCC-Manual konsultieren)
options {
STATIC = true; // alle Parser-operationen sind static
// verwende zwei Token um zu entscheiden, was passieren soll
LOOKAHEAD = 2;
}
// hier beginnt unsere Parser Klasse ("MathParse")
PARSER_BEGIN(MathParse)
// hier kann ganz normaler Java-Code verwendet werden
public class MathParse {
public static void main(String[] args) {
// auch ein statischer Parser muss initiiert werden
// - allerdings nur einmal
MathParse parser = new MathParse(System.in);
try {
System.out.println(parser.parse());
} catch(ParseException e) {
e.printStackTrace();
}
}
// die Parser-Methoden werden automatisch hinzugefügt
}
PARSER_END(MathParse)
// Diese Zeichen ignorieren wir
// SKIP : { $regex$ }
SKIP : { " " | "\t" }
// Jetzt definieren wir unsere Token
// TOKEN : { < $tokenname$ : $regex$ >}
// "NUMBER" entspricht einer unbegrenzten Anzahl (min. 1) an Zahlen
// (von 0 bis 9)
TOKEN : { < NUMBER : (["0"-"9"])+ ("." (["0"-"9"])+)? > }
TOKEN : { < EOL : "\n" > }
// Und fröhlich weiter mit der tatsächlichen Syntax
double parse() : {
double value;
}
{
value=expr()
(<EOF> | <EOL>) { return value; }
}
double expr() : {
double x;
double y;
}
{
x=term()
(
"+" y=expr() { x += y; }
|
"-" y=expr() { x -= y; }
)*
{ return x; }
}
double term() : {
double x;
double y;
}
{
x=value()
(
"*" y=term() { x *= y; }
|
"/" y=term() { x /= y; }
)*
{ return x; }
}
double value() : {
double value;
}
{
"-" value=number() { return -value; }
|
value=number() { return value; }
}
double number() : {
Token t;
double value;
}
{
t=<NUMBER> { return Double.parseDouble(t.image); }
|
"(" value=expr() ")" { return value; }
}
效果很好。 但现在我不想得到一个数字作为结果,而是一个代表该术语的类结构。 我想到了这样的事情:
public abstract class Expression {
public abstract double calculate();
}
public class NumberExpression extends Expression {
public double Value;
public NumberExpression(double value) {
this.Value = value;
}
public double calculate() {
return this.Value;
}
}
public class ComplexExpression extends Expression {
public Operator Operator;
public Vector SubExpressions;
public double calculate() {
double result = ((Expression)this.SubExpressions.elementAt(0)).calculate();
for (int i = 1; i < this.SubExpressions.size(); ++i)
result = this.Operator.calculate(result, ((Expression)this.SubExpressions.elementAt(i)).calculate());
return result;
}
}
public abstract class Operator {
public abstract String getOperator();
public abstract double calculate(double x, double y);
}
我与 Java 或 JavaCC 没有太多关系,所以你能告诉我如何为此编写语法吗?
PS:我使用的是Java ME。
I'm using this grammar to calculate math expressions:
// Konfiguration (JavaCC-Manual konsultieren)
options {
STATIC = true; // alle Parser-operationen sind static
// verwende zwei Token um zu entscheiden, was passieren soll
LOOKAHEAD = 2;
}
// hier beginnt unsere Parser Klasse ("MathParse")
PARSER_BEGIN(MathParse)
// hier kann ganz normaler Java-Code verwendet werden
public class MathParse {
public static void main(String[] args) {
// auch ein statischer Parser muss initiiert werden
// - allerdings nur einmal
MathParse parser = new MathParse(System.in);
try {
System.out.println(parser.parse());
} catch(ParseException e) {
e.printStackTrace();
}
}
// die Parser-Methoden werden automatisch hinzugefügt
}
PARSER_END(MathParse)
// Diese Zeichen ignorieren wir
// SKIP : { $regex$ }
SKIP : { " " | "\t" }
// Jetzt definieren wir unsere Token
// TOKEN : { < $tokenname$ : $regex$ >}
// "NUMBER" entspricht einer unbegrenzten Anzahl (min. 1) an Zahlen
// (von 0 bis 9)
TOKEN : { < NUMBER : (["0"-"9"])+ ("." (["0"-"9"])+)? > }
TOKEN : { < EOL : "\n" > }
// Und fröhlich weiter mit der tatsächlichen Syntax
double parse() : {
double value;
}
{
value=expr()
(<EOF> | <EOL>) { return value; }
}
double expr() : {
double x;
double y;
}
{
x=term()
(
"+" y=expr() { x += y; }
|
"-" y=expr() { x -= y; }
)*
{ return x; }
}
double term() : {
double x;
double y;
}
{
x=value()
(
"*" y=term() { x *= y; }
|
"/" y=term() { x /= y; }
)*
{ return x; }
}
double value() : {
double value;
}
{
"-" value=number() { return -value; }
|
value=number() { return value; }
}
double number() : {
Token t;
double value;
}
{
t=<NUMBER> { return Double.parseDouble(t.image); }
|
"(" value=expr() ")" { return value; }
}
That works fine. But now I don't want to get a number as the result, but a class structure representing the term. I thought of something like this:
public abstract class Expression {
public abstract double calculate();
}
public class NumberExpression extends Expression {
public double Value;
public NumberExpression(double value) {
this.Value = value;
}
public double calculate() {
return this.Value;
}
}
public class ComplexExpression extends Expression {
public Operator Operator;
public Vector SubExpressions;
public double calculate() {
double result = ((Expression)this.SubExpressions.elementAt(0)).calculate();
for (int i = 1; i < this.SubExpressions.size(); ++i)
result = this.Operator.calculate(result, ((Expression)this.SubExpressions.elementAt(i)).calculate());
return result;
}
}
public abstract class Operator {
public abstract String getOperator();
public abstract double calculate(double x, double y);
}
I didn't have much to do with Java or JavaCC, so can you tell me how to write a grammar for that?
PS: I'm using Java ME.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
eWolf,
尝试使用 JJTree,它是 JavaCC 的预处理器,并自动引入为解析输入创建抽象语法树的 java 代码。
只需访问 https://javacc.dev.java.net/ 并找到 JJTree 手册。
eWolf,
Try using JJTree which is a preprocessor for JavaCC and automatically introduces java code that creates Abstract Syntax Trees for parsed input.
Just visit https://javacc.dev.java.net/ and find the JJTree manual.