语法分析实现–语句解析实现
1. 目标及代码
- 目标: 在语法分析实现1 中已经实现了表达式得解析, 接下来需要实现得就是具体语句得解析
如: a = 1+2*5 赋值语句, if语句,while语句等语句解析实现, 目标依然是将Token流解析为语法树
-
代码地址: git代码仓库
-
注意: 本文章主要目的是记录个人学习历程,如有不对的地方欢迎大家评论指出
2. 实现前分析
- 注意:不必一次性创建完成,可分部分实现
3. 具体实现
3.1 声明语句实现
- 创建抽象得Stmtement语句类
/**
* 语句节点
*/
public abstract class Stmtment extends GrammerNode {
public Stmtment(GrammerNodeTypes type, String label) {
super(type, label);
}
}
- 实现DeclareStatement
- 分析
- 声明语句此处不包含不给初始值得情况
- 基本形式:DeclareStmtment -> var variable = Expr , 其中Expr和之前得定义相同
- 也就是我们得语句是没有分号结束得
- 分析
public class DeclareStmtment extends Stmtment {
public DeclareStmtment() {
super(GrammerNodeTypes.DECLARE_STMT, "declare");
}
/**
* var age = 1 + pre
* var age = 12
* @param it
* @return
* @throws ParseException
*/
public static GrammerNode parse(PeekTokenIterator it) throws ParseException {
// 首先判断是否为var 并消费掉
DeclareStmtment declareStmtment = new DeclareStmtment();
Token token = it.peek();
it.nextMatch("var");
// left
Token name = it.peek();
GrammerNode declareName = Factor.parse(it);
if (declareName == null) {
throw new ParseException(name);
}
declareStmtment.addChild(declareName);
//curNode
Token lexme = it.nextMatch("=");
declareStmtment.setToken(lexme);
//right
GrammerNode expr = Expr.parse(it);
declareStmtment.addChild(expr);
return declareStmtment;
}
}
- 测试用列
public class DeclareStatmentTest {
@Test
public void test() throws ParseException {
String declareStr = "var name = id + 1 + 1";
GrammerNode node = execParse(declareStr);
String s = ParserUtils.toPostfixExpression(node);
System.out.println(s);
}
public GrammerNode execParse(String code) throws ParseException {
Lexer lexer = new Lexer();
List<Token> tokens = lexer.analyse(code.chars().mapToObj(o -> (char) o));
GrammerNode resNode = DeclareStmtment.parse(new PeekTokenIterator(tokens.stream()));
return resNode;
}
}
3.2 赋值语句实现
- 分析:
- 赋值语句实际上和声明语句得区别在于没有前置得var
- 基本形式:AssignStmt -> variable = Expr
- 具体实现
/**
* 赋值语句
* name = 123
* age = a + b
* variable = Expr
*/
public class AssignStmt extends Stmtment {
public AssignStmt() {
super(GrammerNodeTypes.ASSIGN_STMT, "designStatement");
}
public static GrammerNode parse(PeekTokenIterator it) throws ParseException {
AssignStmt assignStmt = new AssignStmt();
// 1.首先赋值语句一定是一个variable开头
Token peek = it.peek();
if (!peek.isVariable()) {
throw new ParseException(peek);
}
GrammerNode variable = Factor.parse(it);
assignStmt.addChild(variable);
//变量名过后一定为一个赋值符号
Token equalSymbol = it.peek();
it.nextMatch("=");
assignStmt.setToken(equalSymbol);
// 等号后面为一个表达式Expr
assignStmt.addChild(Expr.parse(it));
return assignStmt;
}
}
- 测试用列
/**
* 赋值语句
* name = 123
* age = a + b
* variable = Expr
*/
public class AssignStmtTest {
@Test
public void test() throws ParseException {
String declareStr = "name = id + 1 + 1";
GrammerNode node = execParse(declareStr);
String s = ParserUtils.toPostfixExpression(node);
System.out.println(s);
}
public GrammerNode execParse(String code) throws ParseException {
Lexer lexer = new Lexer();
List<Token> tokens = lexer.analyse(code.chars().mapToObj(o -> (char) o));
GrammerNode resNode = AssignStmt.parse(new PeekTokenIterator(tokens.stream()));
return resNode;
}
}
3.3 语句块儿实现
-
分析:
-
语句块儿是什么, 类似在Java中我们写得一下代码
{ name = "123"; String id = "11223"; }
-
为什么需要语句块儿
- 因为我们得if语句以及while/for等都是有一个语句块儿的
-
一般形式
- BlockStmt -> { [Stmt]* }, 其中*代表0个或多个Stmt
-
-
具体实现
- 注意:此处的Stmtment.parse(it)还没有具体实现,只是目前假设当前的抽象Stamtement对象能够提供一个方法解析任何类型的语句返回语句根节点(目前只有声明语句以及赋值语句)
/**
* 语句块儿, 在一对花括号中的代码
*
*/
public class BlockStmt extends Stmtment {
public BlockStmt() {
super(GrammerNodeTypes.BLOCK_STMT, "blockStatement");
}
public static GrammerNode parse(PeekTokenIterator it) throws ParseException {
BlockStmt blockStatement = new BlockStmt();
//首先正确消费掉{
it.nextMatch("{");
//循环解析Stmt
GrammerNode item = null;
while ((item = Stmtment.parse(it)) != null) {
blockStatement.addChild(item);
}
it.nextMatch("}");
return blockStatement;
}
}
3.4 Statment中实现任何类型语句解析
- 分析
- 在此类中只需要判断当前符号流属于哪种语句然后直接调用对应的实现去解析即可
/**
* 语句节点
*/
public abstract class Stmtment extends GrammerNode {
public Stmtment(GrammerNodeTypes type, String label) {
super(type, label);
}
protected static GrammerNode parse(PeekTokenIterator it) throws ParseException {
if(!it.hasNext()) {
return null;
}
Token peek = it.next();
// 向前看两位,用于判断是否为赋值语句
Token lookahead = it.peek();
// 退还next位
it.putBack();
if ("var".equals(peek.getValue())) {
return DeclareStmtment.parse(it);
} else if (peek.isVariable() && lookahead != null && "=".equals(lookahead.getValue())) {
return AssignStmt.parse(it);
}
return null;
}
}
3.5 测试BlockStmt语句
- 注意此处语句块儿中的多条语句是直接以换行来区分的
/**
* 赋值语句
* name = 123
* age = a + b
* variable = Expr
*/
public class BlockStmtTest {
@Test
public void test() throws ParseException {
String declareStr = " {\n" +
" age = \"123\"\n" +
" var name = id\n" +
" }";
GrammerNode node = execParse(declareStr);
String s = ParserUtils.toPostfixExpression(node);
System.out.println(s);
}
public GrammerNode execParse(String code) throws ParseException {
Lexer lexer = new Lexer();
List<Token> tokens = lexer.analyse(code.chars().mapToObj(o -> (char) o));
GrammerNode resNode = BlockStmt.parse(new PeekTokenIterator(tokens.stream()));
return resNode;
}
}
3.6 IF语句实现
-
分析:
-
基本形式
IFStmt -> if(expr) block tail tail -> else block | else IFStmt | null
-
-
具体实现
/**
* IFStmt -> if(expr) block tail
* tail -> else block | else IFStmt | null
*/
public class IFStmt extends Stmtment {
public IFStmt() {
super(GrammerNodeTypes.IF_STMT, "if");
}
public static GrammerNode parse(PeekTokenIterator it) throws ParseException {
IFStmt ifStmt = new IFStmt();
Token peek = it.peek();
it.nextMatch("if");
ifStmt.setToken(peek);
// 解析表达式
it.nextMatch("(");
GrammerNode expr = Expr.parse(it);
if (null == expr) {
throw new ParseException("if表达式解析错误");
}
ifStmt.addChild(expr);
it.nextMatch(")");
// 解析语句块儿
GrammerNode block = BlockStmt.parse(it);
if (null == block) {
throw new ParseException("语句块儿不可为空");
}
ifStmt.addChild(block);
// 解析tail
GrammerNode tail = parseTail(it);
if (null != tail) {
ifStmt.addChild(tail);
}
return ifStmt;
}
/**
* tail -> else block | else IFStmt | null
* 实际上此处只有两种类型结果
* 1. block
* 2. ifStmt
* @param it
* @return
*/
private static GrammerNode parseTail(PeekTokenIterator it) throws ParseException {
if(!it.hasNext() || !it.peek().getValue().equals("else")) {
return null;
}
//消费掉else
it.nextMatch("else");
Token lookahead = it.peek();
if("{".equals(lookahead.getValue())) {
// 语句块儿
return BlockStmt.parse(it);
} else if ("if".equals(lookahead.getValue())) {
return IFStmt.parse(it);
}
return null;
}
}
- 测试用列
public class IFStmtTest {
{
}
@Test
public void test() throws ParseException {
String declareStr = " if (a == 25) {\n" +
" a = 23\n" +
" } else if (a == 22) {\n" +
" a = 1 + 3\n" +
" } else {\n" +
" a = 12\n" +
" }";
GrammerNode node = execParse(declareStr);
String s = ParserUtils.toPostfixExpression(node);
System.out.println(s);
}
public GrammerNode execParse(String code) throws ParseException {
Lexer lexer = new Lexer();
List<Token> tokens = lexer.analyse(code.chars().mapToObj(o -> (char) o));
GrammerNode resNode = IFStmt.parse(new PeekTokenIterator(tokens.stream()));
return resNode;
}
}
3.7while语句解析
-
分析
-
基本形式
whileStmt -> while(expr) block
-
-
具体实现
/** * while循环语句 */ public class WhileStmt extends Stmtment { public WhileStmt() { super(GrammerNodeTypes.WHILE_STMT, "WHILE"); } public static GrammerNode parse(PeekTokenIterator it) throws ParseException { WhileStmt whileStmt = new WhileStmt(); Token peek = it.peek(); it.nextMatch("while"); // curNode whileStmt.setToken(peek); //解析条件表达式 left node it.nextMatch("("); GrammerNode expr = Expr.parse(it); if (null == expr) { throw new ParseException("while需要条件表达式"); } whileStmt.addChild(expr); it.nextMatch(")"); //解析循环体 Block GrammerNode whileBlock = BlockStmt.parse(it); if (null == whileBlock) { throw new ParseException("while必须包含循环体"); } whileStmt.addChild(whileBlock); return whileStmt; } }
-
测试用列
public class WhileStmtTest {
// {
// while (a == 2) {
// a = 4
// }
// }
@Test
public void test() throws ParseException {
String declareStr = " while (a == 2) {\n" +
" a = 4\n" +
" }";
GrammerNode node = execParse(declareStr);
String s = ParserUtils.toPostfixExpression(node);
System.out.println(s);
}
public GrammerNode execParse(String code) throws ParseException {
Lexer lexer = new Lexer();
List<Token> tokens = lexer.analyse(code.chars().mapToObj(o -> (char) o));
GrammerNode resNode = WhileStmt.parse(new PeekTokenIterator(tokens.stream()));
return resNode;
}
}
3.8函数解析
-
分析
- 目标函数结构
func funcName(args) returnType{ .... return }
- 函数组成部分
- 函数名
- 函数参数
- 返回值类型
- 函数文法
Function -> func variable(args) returnType Block args -> Type variable, args | Type variable | null returnType -> Type Type -> int|String|....
3.8.1 返回语句解析实现
- 分析: 返回语句基本形式: ReturnStmt -> return expr
- 注意添加语句之后需要到Stmtement抽象类中补全parse方法
/**
* 解析返回语句
*/
public class ReturnStmt extends Stmtment {
public ReturnStmt() {
super(GrammerNodeTypes.RETURN_STMT, "RETURN_STMT");
}
/**
* 基本形式 ReturnStmt -> return expr
* @param it
* @return
*/
public static GrammerNode parse(PeekTokenIterator it) throws ParseException {
Token returnToken = it.nextMatch("return");
GrammerNode expr = Expr.parse(it);
ReturnStmt returnStmt = new ReturnStmt();
returnStmt.setToken(returnToken);
if (null != expr)
returnStmt.addChild(expr);
return returnStmt;
}
}
- 补全代码
protected static GrammerNode parse(PeekTokenIterator it) throws ParseException {
if(!it.hasNext()) {
return null;
}
Token peek = it.next();
// 向前看两位,用于判断是否为赋值语句
Token lookahead = it.peek();
// 退还next位
it.putBack();
if ("var".equals(peek.getValue())) {
return DeclareStmtment.parse(it);
} else if (peek.isVariable() && lookahead != null && "=".equals(lookahead.getValue())) {
return AssignStmt.parse(it);
} else if (peek.getValue().equals("return")) {
return ReturnStmt.parse(it);
}else if(peek.getValue().equals("if")) {
return IFStmt.parse(it);
}
return null;
}
3.8.2 参数解析实现
-
分析
- 基本形式
args -> Type variable, args | Type variable | nulls
-
具体实现
/**
* 函数参数
*/
public class FunctionArgsStmt extends Stmtment {
public FunctionArgsStmt() {
super(GrammerNodeTypes.FUNC_ARGS_STMT, "FUNC_ARGS");
}
/**
* args -> Type variable, args | Type variable | null
*/
public static GrammerNode parse(PeekTokenIterator it) throws ParseException {
FunctionArgsStmt args = new FunctionArgsStmt();
while(it.peek().isType()) {
Token type = it.next();
Variable variable = (Variable)Factor.parse(it);
if (null == variable) {
throw new ParseException("func参数解析异常");
}
variable.setTypeToken(type);
args.addChild(variable);
if(!it.peek().getValue().equals(")")) {
it.nextMatch(",");
}
}
return args;
}
}
3.8.3 函数解析
/**
* 函数参数
*/
public class FunctionArgsStmt extends Stmtment {
public FunctionArgsStmt() {
super(GrammerNodeTypes.FUNC_ARGS_STMT, "FUNC_ARGS");
}
/**
* args -> Type variable, args | Type variable | null
*/
public static GrammerNode parse(PeekTokenIterator it) throws ParseException {
FunctionArgsStmt args = new FunctionArgsStmt();
while(it.peek().isType()) {
Token type = it.next();
Variable variable = (Variable)Factor.parse(it);
if (null == variable) {
throw new ParseException("func参数解析异常");
}
variable.setTypeToken(type);
args.addChild(variable);
if(!it.peek().getValue().equals(")")) {
it.nextMatch(",");
}
}
return args;
}
}
- 测试用列
public class FuncStmtTest {
@Test
public void test() throws ParseException {
String declareStr = " func testfunc(int a, string b) float {\n" +
" var a = 12 + 3\n" +
" }";
GrammerNode node = execParse(declareStr);
String s = ParserUtils.toPostfixExpression(node);
System.out.println(s);
}
public GrammerNode execParse(String code) throws ParseException {
Lexer lexer = new Lexer();
List<Token> tokens = lexer.analyse(code.chars().mapToObj(o -> (char) o));
GrammerNode resNode = FunctionStmt.parse(new PeekTokenIterator(tokens.stream()));
return resNode;
}
}
4. 程序解析实现
-
分析
- 程序: 程序实际上就类似一个语句块儿但是不同得是这个语句块儿不需要花括号
-
具体实现
/** * 程序代码块儿 */ public class Program extends BlockStmt { public Program() { super(); } public static GrammerNode parse(PeekTokenIterator it) throws ParseException { Program block = new Program(); GrammerNode stmt = null; while( (stmt = Stmtment.parse(it)) != null) { block.addChild(stmt); } return block; } }