Java中的递归下降解析器
首先,我想说这是我第三年编程语言课的家庭作业,我正在寻求一些帮助。我的作业是: 截止日期:2013年2月22日晚上11:55Java中的递归下降解析器,java,parsing,recursion,Java,Parsing,Recursion,首先,我想说这是我第三年编程语言课的家庭作业,我正在寻求一些帮助。我的作业是: 截止日期:2013年2月22日晚上11:55 提交:请将以下内容上传至CMS 1.源代码 2.程序执行的屏幕截图,包括您使用的输入文件 使用您喜欢的任何编程语言编写递归下降解析器,该解析器解析由以下EBNF描述生成的语言。解析器应该检测输入程序是否有语法错误。它不必指定错误的内容和位置 仅供参考,我的解析器的示例输入程序是 begin total = var1 + var2; while (var1 < v
提交:请将以下内容上传至CMS
1.源代码
2.程序执行的屏幕截图,包括您使用的输入文件 使用您喜欢的任何编程语言编写递归下降解析器,该解析器解析由以下EBNF描述生成的语言。解析器应该检测输入程序是否有语法错误。它不必指定错误的内容和位置 仅供参考,我的解析器的示例输入程序是
begin
total = var1 + var2;
while (var1 < var2)
while ( var3 > var4)
var2 = var2 - var1
end
开始
总计=var1+var2;
while(var1var4)
var2=var2-var1
结束
解析器代码的结构应该类似于语言语法的结构。
例如
您可能不希望将令牌处理(扫描器)与结构解析(解析器)混淆
对于错误处理,我将使用异常处理而不是if/else结构。
您可能希望跟踪您在源(扫描仪)部件中的位置,以便显示正确的错误消息。只需询问扫描仪的状态
幸运的是,这项任务似乎不需要解决冲突,因此您的递归任务应该可以很好地完成。有趣的部分是解析
<while_stmt> ::= while (<logic_expr>) <stmt>
::=while()
您最终将递归调用parse_stmt()
。这就是递归下降解析的全部思想 1)标记化
首先将输入分解为令牌。在本例中,每个标识符、运算符和文本都是。制作一个所有输入标记的大列表。一旦有了令牌,就可以开始解析了。使令牌成为一个链表,这样您就可以说Token.Next来读取下一个令牌或Token.Next.Next来读取前面的2个令牌。在末尾放一堆EOF标记,这样你就永远不会跳过它
2) 解析
解析就像您已经拥有的一样。因此,与其思考符号,不如思考令牌。Parse Statements列表是一个while循环,它将解析语句保持到最后
For Parse语句
public void parseStmt ()
{
if (Token.kind == KEYWORD && Token.id == kw_while) {
return ParseWhileStatement();
}
else {
return ParseAssignStatement();
}
}
解析while语句将循环回parse语句,因此它将“递归下降”回parse语句,生成嵌套的while循环等
解析赋值语句非常类似。先分析左侧,然后分析右侧。你需要一堆函数来实现这一点
这里的节点是Ast节点。抽象语法树
像
class Node {
}
class OpNode {
OpNode Lhs;
OpNode Rhs;
}
class MultiplyNode : OpNode {
MultiplyNode(byref Token tok, OpNode Left, OpNode right) {
tok = tok.Next;
Lhs = left;
Rhs = right;
}
}
Node ParseSimpleExp() {
if (Token.kind == Identifier) {
Node n = new IdentNode;
NextToken();
return n;
}
if (Token.kind == Number) {
Node n = new NumberNode;
NextToken();
return n;
}
}
// In these examples move the token to next token when you create the new nodes
Node ParseMulExp() {
Node n = ParseSimpleExp();
while (1) {
if (Token.Kind == Multiply) {
n = new MultiplyNode(Token,n,ParseSimpleExp());
continue;
}
if (Token.Kind == Divide) {
n = new DivideNode(Token,n,ParseSimpleExp());
continue;
}
return n;
}
}
Node ParseAddExp() {
Node n = ParseMulExp();
while (1) {
if (Token.Kind == Add) {
n = new AddNode(Token,n,ParseMulExp());
continue;
}
if (Token.Kind == Subtract) {
n = new SubtractNode(Token,n,ParseMulExp());
continue;
}
return n;
}
}
Node ParseAssignStatement() {
Node n = ParseAddExp();
if (Token.kind == ASSIGN) {
return new AssignStatement(Token,n,ParseAddExp());
}
}
如果遵循逻辑,您可以看到递归地到达每个目标是如何遵循优先规则的。解析表达式并从赋值开始不是一个循环。如图所示。显然这很简单,但它展示了技术
因此,RDP是由查看当前令牌,然后跳转到某个函数来处理令牌引起的。当然,这可以返回到同一个函数,因此是递归的。如果您查看ParseSimpleExp函数,您会发现这是处理括号表达式的好地方。parens表达式将导致递归返回到simple exp,也可能是所有其他表达式,如mul和add。根据此特定赋值,可以使用函数方式进行字符串处理 尝试以下算法:
begin
开头,以end
结尾拆分剩余字符串代码>并对每个零件(语句)执行以下步骤
=
或while
子字符串+
或-
拆分输入,并为每个部分检查变量条件(字母数字内容)(
和)
并递归处理括号之间和括号之后的两个字符串public enum Parser {
PROGRAM {
void parse(String s) throws ParseException {
s = s.trim();
if (s.startsWith("begin") && s.endsWith("end")) {
STATEMENT_LIST.parse(s.substring(5, s.length() - 3));
} else {
throw new ParseException("Illegal begin/end");
}
}
},
STATEMENT_LIST {
void parse(String s) throws ParseException {
String[] parts = s.trim().split(";");
for (String part : parts) {
STATEMENT.parse(part.trim());
}
}
},
STATEMENT {
void parse(String s) throws ParseException {
if (s.startsWith("while")) {
WHILE.parse(s.substring(5));
} else if (s.contains("=")) {
ASSIGNMENT.parse(s);
} else {
throw new ParseException("Illegal statement: " + s);
}
}
},
WHILE {
void parse(String s) throws ParseException {
int i = s.indexOf("(");
int j = s.indexOf(")");
if (i != -1 && j != -1) {
LOGICAL.parse(s.substring(i + 1, j).trim());
STATEMENT.parse(s.substring(j + 1).trim());
} else {
throw new ParseException("Illegal while: " + s);
}
}
},
ASSIGNMENT {
void parse(String s) throws ParseException {
int i = s.indexOf("=");
if (i != -1) {
VARIABLE.parse(s.substring(0, i).trim());
EXPRESSION.parse(s.substring(i + 1).trim());
}
}
},
EXPRESSION {
void parse(String s) throws ParseException {
String[] parts = s.split("\\+|-");
for (String part : parts) {
VARIABLE.parse(part.trim());
}
}
},
LOGICAL {
void parse(String s) throws ParseException {
int i;
if (s.contains("<")) {
i = s.indexOf("<");
} else if (s.contains(">")) {
i = s.indexOf(">");
} else {
throw new ParseException("Illegal logical: " + s);
}
VARIABLE.parse(s.substring(0, i).trim());
VARIABLE.parse(s.substring(i + 1).trim());
}
},
VARIABLE {
void parse(String s) throws ParseException {
if (!s.matches("^[a-zA-Z][a-zA-Z0-9]*$")) {
throw new ParseException("Illegal variable: " + s);
}
}
};
abstract void parse(String s) throws ParseException;
public static void main(String[] args) {
try {
PROGRAM.parse("begin \n" +
"total = var1 + var2; \n" +
"while (var1 < var2) \n" +
"while ( var3 > var4)\n" +
"var2 = var2 - var1 \n" +
"end");
System.out.println("OK");
} catch (ParseException e) {
System.out.println(e.getMessage());
}
}
}
class ParseException extends Exception {
public ParseException(String message) {
super(message);
}
}
公共枚举解析器{
节目{
void parse(字符串s)引发ParseException{
s=s.修剪();
如果(s.startsWith(“开始”)和s.endsWith(“结束”)){
语句_LIST.parse(s.substring(5,s.length()-3));
}否则{
抛出新的ParseException(“非法开始/结束”);
}
}
},
报表清单{
void parse(字符串s)引发ParseException{
String[]parts=s.trim().split(;);
用于(字符串部分:部分){
parse(part.trim());
}
}
},
声明{
void parse(字符串s)引发ParseException{
如果(s.startsWith(“while”)){
WHILE.parse(s.substring(5));
}如果包含(“=”),则为else{
赋值。解析;
}否则{
抛出新的ParseException(“非法语句:+s”);
}
}
},
当{
void parse(字符串s)引发ParseException{
int i=s.indexOf(“”);
int j=s.indexOf(“)”;
如果(i!=-1&&j!=-1){
LOGICAL.parse(s.substring(i+1,j.trim());
parse(s.substring(j+1.trim());
}否则{
抛出新的ParseException(“非法的while:+s”);
}
}
},
分配{
void parse(字符串s)引发ParseException{
int i=s.indexOf(“=”);
如果(i!=-1){
parse(s.substring(0,i.trim());
parse(s.substring(i+1.trim());
}
}
},
表情{
void parse(字符串s)引发ParseException{
斯特林
<while_stmt> ::= while (<logic_expr>) <stmt>
public void parseStmt ()
{
if (Token.kind == KEYWORD && Token.id == kw_while) {
return ParseWhileStatement();
}
else {
return ParseAssignStatement();
}
}
class Node {
}
class OpNode {
OpNode Lhs;
OpNode Rhs;
}
class MultiplyNode : OpNode {
MultiplyNode(byref Token tok, OpNode Left, OpNode right) {
tok = tok.Next;
Lhs = left;
Rhs = right;
}
}
Node ParseSimpleExp() {
if (Token.kind == Identifier) {
Node n = new IdentNode;
NextToken();
return n;
}
if (Token.kind == Number) {
Node n = new NumberNode;
NextToken();
return n;
}
}
// In these examples move the token to next token when you create the new nodes
Node ParseMulExp() {
Node n = ParseSimpleExp();
while (1) {
if (Token.Kind == Multiply) {
n = new MultiplyNode(Token,n,ParseSimpleExp());
continue;
}
if (Token.Kind == Divide) {
n = new DivideNode(Token,n,ParseSimpleExp());
continue;
}
return n;
}
}
Node ParseAddExp() {
Node n = ParseMulExp();
while (1) {
if (Token.Kind == Add) {
n = new AddNode(Token,n,ParseMulExp());
continue;
}
if (Token.Kind == Subtract) {
n = new SubtractNode(Token,n,ParseMulExp());
continue;
}
return n;
}
}
Node ParseAssignStatement() {
Node n = ParseAddExp();
if (Token.kind == ASSIGN) {
return new AssignStatement(Token,n,ParseAddExp());
}
}
public enum Parser {
PROGRAM {
void parse(String s) throws ParseException {
s = s.trim();
if (s.startsWith("begin") && s.endsWith("end")) {
STATEMENT_LIST.parse(s.substring(5, s.length() - 3));
} else {
throw new ParseException("Illegal begin/end");
}
}
},
STATEMENT_LIST {
void parse(String s) throws ParseException {
String[] parts = s.trim().split(";");
for (String part : parts) {
STATEMENT.parse(part.trim());
}
}
},
STATEMENT {
void parse(String s) throws ParseException {
if (s.startsWith("while")) {
WHILE.parse(s.substring(5));
} else if (s.contains("=")) {
ASSIGNMENT.parse(s);
} else {
throw new ParseException("Illegal statement: " + s);
}
}
},
WHILE {
void parse(String s) throws ParseException {
int i = s.indexOf("(");
int j = s.indexOf(")");
if (i != -1 && j != -1) {
LOGICAL.parse(s.substring(i + 1, j).trim());
STATEMENT.parse(s.substring(j + 1).trim());
} else {
throw new ParseException("Illegal while: " + s);
}
}
},
ASSIGNMENT {
void parse(String s) throws ParseException {
int i = s.indexOf("=");
if (i != -1) {
VARIABLE.parse(s.substring(0, i).trim());
EXPRESSION.parse(s.substring(i + 1).trim());
}
}
},
EXPRESSION {
void parse(String s) throws ParseException {
String[] parts = s.split("\\+|-");
for (String part : parts) {
VARIABLE.parse(part.trim());
}
}
},
LOGICAL {
void parse(String s) throws ParseException {
int i;
if (s.contains("<")) {
i = s.indexOf("<");
} else if (s.contains(">")) {
i = s.indexOf(">");
} else {
throw new ParseException("Illegal logical: " + s);
}
VARIABLE.parse(s.substring(0, i).trim());
VARIABLE.parse(s.substring(i + 1).trim());
}
},
VARIABLE {
void parse(String s) throws ParseException {
if (!s.matches("^[a-zA-Z][a-zA-Z0-9]*$")) {
throw new ParseException("Illegal variable: " + s);
}
}
};
abstract void parse(String s) throws ParseException;
public static void main(String[] args) {
try {
PROGRAM.parse("begin \n" +
"total = var1 + var2; \n" +
"while (var1 < var2) \n" +
"while ( var3 > var4)\n" +
"var2 = var2 - var1 \n" +
"end");
System.out.println("OK");
} catch (ParseException e) {
System.out.println(e.getMessage());
}
}
}
class ParseException extends Exception {
public ParseException(String message) {
super(message);
}
}