| L_BRACKET Expression R_BRACKET
---------------------------------------------------------------------------------------------------------------------------
3. 表达式的语法树
(1)语法树的节点
表达式的语法树的节点可以分为以下三类:
?叶节点:用于存放原子表达式,如常数或参数T。
?两个孩子的内部节点:用于存放二元运算如PlUS、MUL等构成的表达式。 ?一个孩子的内部节点:用于存放函数调用如sin(t)等构成的表达式。
可以用下面的一个类统一表示,根据当前记号的类别分配对应的属性,未分配到的属性为默认构造函数初始化时为其赋的值。
语法树(表达式-16+5**3/cos(T))的存储如下所示: PLUS Left Right MINUS Left RightDIV Left Right
CONST_ID 0.0CONST_ID 16POWER Left RightFUNC cos child CONST_ID 5CONST_ID 3 T ptr
parameter
在这里,Java和C不同的是不再提供类似于联合union的结构体,也就是说不再提供非此即彼的功能。本来打算使用一个类,然后将所有的属性都放在里面,用到的则进行赋值,没有用到的则不用理睬。但后来为了使条理更清晰,我们对它进行了改造。在这里,我们使用了内置子类的方法。
public class ExprNode {
public Token_Type OpCode; public Content content; public class Content {
public caseOp CaseOperator; public caseFunc CaseFunc; public double CaseConst; public Double CaseParmPtr;
// 在初始化函数中,我们将它初始化为0 // public double[] CaseParmPtr = new double[1]; // here is very important!!!!!!!!!!!!!!!!!!!!! /**
* Double类型是double的包装类,在JDK1.5以后, 二者可以直接相互赋值,称为自动 * 看你的提示,我推测你的jdk版本在1.5以前。 如果是这样,可以用Double中的方法,
拆箱和自动装箱。
将包装类转为 基本数据类型,如: double
}
public ExprNode() { }
// System.out.println(\OpCode = Token_Type.ERRTOKEN;
// System.out.println(\
// 和词法分析一致,最开始初始化为Token_Type.ERRORTOKEN content = new Content();
// System.out.println(\public Content() { }
CaseOperator = new caseOp(); CaseFunc = new caseFunc(); CaseConst = 0.0;
CaseParmPtr = new Double(0);
public caseFunc() { }
child = null; MathFunPtr = null;
public class caseFunc {
public ExprNode child; public Method MathFunPtr;
* amount = rec.getAmount().doubleValue() ; * * */
// 我们用数组来代替指针 public class caseOp {
public ExprNode Left; public ExprNode Right; public caseOp() { }
Left = null; Right = null;
}// end of class caseOp
}// end of class caseFunc
}// end of class ExprNode
(2)语法树的建立
为了简化语法树的建立过程,我们将待缺省值的函数用参数不同的重载函数来代替,通过传给函数不同类型或者个数的参数进行动态调用,而这也正是C++或者说Java与C的
不同之处。相关代码如下所示:
//-----------------生成语法树的一个节点---------------------------- /**
* every time,we need to allocate new node,and * return it! * */
//叶节点,用于存放参数T
protected ExprNode MakeExprNode(Token_Type opcode) //T { }
//叶节点,用于存放常数CONST_ID
protected ExprNode MakeExprNode(Token_Type opcode,double value) //CONST_ID
//need to modify the type of token,and the value. { }
//一个孩子的内部节点,用于存放函数调用
protected ExprNode MakeExprNode(Token_Type opcode,Method func,ExprNode exprnode) //function { }
// 两个孩子的内部节点,用于存放二元运算
protected ExprNode MakeExprNode(Token_Type opcode,ExprNode left,ExprNode right) //case operation
ExprNode ExprPtr = new ExprNode(); ExprPtr.OpCode = opcode;
ExprNode ExprPtr = new ExprNode(); ExprPtr.OpCode = opcode;
ExprPtr.content.CaseConst = value; return ExprPtr;
ExprNode ExprPtr = new ExprNode(); ExprPtr.OpCode = opcode;
ExprPtr.content.CaseParmPtr = parameter; return ExprPtr;
ExprPtr.content.CaseFunc.MathFunPtr = func; ExprPtr.content.CaseFunc.child = exprnode; return ExprPtr;
{ }
ExprNode ExprPtr = new ExprNode(); ExprPtr.OpCode = opcode;
ExprPtr.content.CaseOperator.Left = left; ExprPtr.content.CaseOperator.Right = right; return ExprPtr;
4. 语法分析器主程序流程图
5. 语法分析器的递归下降子程序
首先,语法分析器以下的几个函数中需要用到词法分析为其提供的内容: public void FetchToken();
public void MatchToken(Token_Type AToken); public void SyntaxError(int case_of); 词法分析器为其提供的内容如下所示: 函数public GetToken(); 记号类型TokenType; 全局变量行号int LineNo;
词法分析器、语法分析器、语义分析器三者之间的调用关系如下所示
(1)主要产生式的递归子程序
递归下降子程序分为两类,返回值为void类型的函数实现相应的产生式,返回值为ExprNode类型的函数对表达式进行语法分析的同时为其构造语法树。
--------------------------------------------------------产生式函数-------------------------------------------------------
public void Program(); public void Statement(); public void OriginStatement(); public void ScaleStatement(); public void RotStatement(); public void ForStatement();
-------------------------------------------------------语法树构造函数-------------------------------------------------------
public ExprNode Expression(); public ExprNode Term(); public ExprNode Factor(); public ExprNode Component(); public ExprNode Atom();
三、测试例程设计与测试结果分析
1. 例程1
(1) 测试用例分析
首先,我们来做一个最简单的测试用例,用它实现语法分析器的各项基本要求。 (2) 测试结果
在test1.txt中内容如下: --here are notes.
for T from 0 to 120 step 1 draw (t, -t); 测试结果如下: