Java中的递归下降解析器

Java中的递归下降解析器,java,parsing,recursion,Java,Parsing,Recursion,首先,我想说这是我第三年编程语言课的家庭作业,我正在寻求一些帮助。我的作业是: 截止日期:2013年2月22日晚上11:55 提交:请将以下内容上传至CMS 1.源代码 2.程序执行的屏幕截图,包括您使用的输入文件 使用您喜欢的任何编程语言编写递归下降解析器,该解析器解析由以下EBNF描述生成的语言。解析器应该检测输入程序是否有语法错误。它不必指定错误的内容和位置 仅供参考,我的解析器的示例输入程序是 begin total = var1 + var2; while (var1 < v

首先,我想说这是我第三年编程语言课的家庭作业,我正在寻求一些帮助。我的作业是:

截止日期:2013年2月22日晚上11:55
提交:请将以下内容上传至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
    子字符串
  • 对于分配检查,您可以使用
    +
    -
    拆分输入,并为每个部分检查变量条件(字母数字内容)
  • 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);
    }
    }