ANTLR4初学【打造你我方的语规则定】

  • 首页
  • 关于我们
  • 联系我们
  • 新闻
  • 产品
  • 你的位置:诗意栖居 > 新闻 > ANTLR4初学【打造你我方的语规则定】

    ANTLR4初学【打造你我方的语规则定】

    发布日期:2024-11-09 10:45    点击次数:141

    ANTLR4初学【打造你我方的语规则定】

    著作目次 什么是ANTLR4ANTLR4的特质ANTLR4的语规则定语规则定的声明.g4文献的代码规矩词规则定语规则定语规则定中的操作 若何使用ANTLR4实战IDEA装置ANTLR插件新建技俩创建一个.g4文献通过插件生成java代码创建一个EvalVisitor遍历AST测试 什么是ANTLR4

    ANTLR4(全称为'ANother Tool for Language Recognition')是一种用于构建讲话识别器的纷乱器用。它是一个自动生成的明白器生成器,使用ANTLR4不错匡助建设东谈主员快速创建自界说的讲话或DSL。

    ANTLR4的特质 撑抓多种方针讲话,包括Java、C#、Python、JavaScript等。撑抓LL(*)(LL star)语法分析器,不错科罚包含纵容数意见上前看标记(lookahead)的语法。撑抓词法和语法失误科罚,不错生成明晰的失误讯息和规复政策。撑抓生成AST(概述语法树),浅薄讲话科罚器进行语法分析和代码生成。提供了丰富的API和器用集,不错自界说和优化ANTLR4生成的明白器。 ANTLR4的语规则定 语规则定的声明

    ANTLR4的语规则定必须以“grammar”重要字运行,背面随着语规则定的称号。举例:

    grammar MyGrammar;
    

    这里声明了一个名为'MyGrammar'的语规则定。

    .g4文献的代码规矩 词规则定

    ANTLR4语规则定以词规则定(lexer rules)运行。词规则定界说了输入文本中的各个单词(或标记),这些单词将被语规则定使用。每个词规则定界说一个单词的称号和匹配该单词的正则抒发式。

    以下是一个大约的例子:

    // 界说变量名为一个字母后跟零个或多个字母、数字或下划线
    ID : [a-zA-Z] [a-zA-Z0-9_]*;
    

    在这个例子中,咱们界说了一个名为ID的词规则定,该规矩匹配一个以字母着手,后跟零个或多个字母、数字或下划线的字符串。在语规则定中,咱们不错使用ID来匹配变量名。

    语规则定

    ANTLR4语规则定界说了输入文本的结构。语规则定由词规则定和其他语规则定构成,界说了输入文本的结构。语规则定经常以一个称为start的语规则定运行,这个语规则定界说了通盘这个词输入文本的结构。

    以下是一个大约的例子:

    // 界说一个大约的算术抒发式语规则定
    expr : INT
         | expr op=('*' | '/') expr
         | expr op=('+' | '-') expr
         | '(' expr ')'
         ;
    
    INT : [0-9]+;
    

    在这个例子中,咱们界说了一个名为expr的语规则定,该规矩界说了一个大约的算术抒发式。该规矩由四个子规矩构成,每个子规矩界说了一种抒发式。第一个子规矩匹配整数,第二个和第三个子规矩匹配乘法、除法、加法和减法,终末一个子规矩匹配括号中的抒发式。咱们还界说了一个名为INT的词规则定,该规矩匹配一个或多个数字。在这个例子中,咱们使用INT来匹配整数。

    语规则定中的操作
    // 界说一个带有语义谓词的语规则定
    expr : INT { $INT.text.equals('0')}
    

    在这个例子中,咱们界说了一个名为expr的语规则定,该规矩匹配整数,并使用语义谓词来指定该规矩是否适用于输入文本。在这个例子中,语义谓词检查整数是否为零。

    若何使用ANTLR4

    下载并装置ANTLR4:只需要下载官方网站上提供的ANTLR4 JAR文献,然后将其添加到您的Java类旅途中即可。您还不错选用装置ANTLR4插件来集成到您的IDE中,以便更浅薄地使用ANTLR4。底下咱们演示如安在IDEA中使用ANTLR4插件。

    编写语法文献:在ANTLR4中,您需要编写一个.g4文献来界说词法和语规则定。您不错使用文本剪辑器编写.g4文献。

    生成代码:一朝您编写了.g4文献,您不错使用ANTLR4生成Java代码。使用以下号令不错生成Java代码:

    java -jar antlr-4.9.2-complete.jar YourGrammar.g4
    

    在上头的号令中,您需要将YourGrammar.g4替换为您的.g4文献的称号。

    编写明白器:一朝您生成了Java代码,您不错编写一个Java明白器来明白输入文本。您不错使用ANTLR4提供的Java API来编写明白器。
    CharStream input = CharStreams.fromStream(System.in);
    YourGrammarLexer lexer = new YourGrammarLexer(input);
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    YourGrammarParser parser = new YourGrammarParser(tokens);
    YourGrammarParser.StartContext tree = parser.start();
    

    在上头的代码中,您需要将YourGrammarLexer和YourGrammarParser替换为您生成的Lexer和Parser类的称号。您还需要替换start()身手,该身手应该复返您的语规则定中的start规矩的ParseTree对象。

    实战

    咱们来作念一个具体的例子,经典的筹算器,主如果终了四则运算,带括号等等。

    IDEA装置ANTLR插件

    File->Settings->Plugins->Marketplace

    图片

    新建技俩

    新建一个maven技俩

    图片

    pom.xml引入antlr的依赖
                <dependency>
                    <groupId>org.antlr</groupId>
                    <artifactId>antlr4-runtime</artifactId>
                    <version>4.10.1</version>
                </dependency>
    
    创建一个.g4文献

    图片

    grammar Arithmetic;
    
    /*
     * Parser rules
     */
    
    parse
        : expr EOF
        ;
    
    expr
        : term (('+'|'-') term)*
        ;
    
    term
        : factor (('*'|'/') factor)*
        ;
    
    factor
        : NUMBER
        | '(' expr ')'
        ;
    
    /*
     * Lexer rules
     */
    
    NUMBER
        : DIGIT+ ('.' DIGIT+)?
        ;
    
    DIGIT
        : [0-9]
        ;
    
    WHITESPACE
        : [ \t\n\r] -> skip
        ;
    
    

    在这个语规则定中,咱们界说了四个规矩:

    parse:最高档别的规矩,暗意一个齐全的抒发式。它由一个expr规矩背面随着一个EOF标记构成。expr:暗意一个加法或减法抒发式。它由一个term规矩背面随着零个或多个加法或减法标识,背面再随着一个term规矩构成。term:暗意一个乘法或除法抒发式。它由一个factor规矩背面随着零个或多个乘法或除法标识,背面再随着一个factor规矩构成。factor:暗意一个数字或括号内的抒发式。它不错是一个数字,或者是一个由左括号、一个抒发式和右括号构成的组合。

    注重,在这个示例中,咱们还界说了一些Lexer规矩,用于识别数字和忽略空格和换行符。

    咱们不错通过idea的antlr插件来检查咱们的语规则定: 如下图,点击ANTLR Preview不错来到如下界面。左边的框填写需要校验的抒发式,右边等于语法树明白的效果。

    图片

    接下来,咱们需要使用ANTLR来生成Java代码。 通过插件生成java代码

    右键.g4文献,选用Configure ANTLR,设立java文献的生成旅途。

    图片

    图片

    再次右键.g4文献,选用Generate ANTLR Reconizer 即可生成java代码

    图片

    创建一个EvalVisitor遍历AST

    咱们创建一个EvalVisitor遍历AST,并筹算抒发式的值。最终,咱们打印筹算效果。 EvalVisitor是一个咱们需要我方终了的类,它摄取了ArithmeticBaseVisitor,并重写了其中的身手。底下是一个大约的终了示例: 新建类EvalVisitor.java

    public class EvalVisitor  extends ArithmeticBaseVisitor<Double> {
        // 使用一个Map来存储变量名和值的映射联系
        Map<String, Double> memory = new HashMap<String, Double>();
    
    
        // 重写visitExpr身手,用于筹算加法和减法
        @Override
        public Double visitExpr(ArithmeticParser.ExprContext ctx) {
            Double result = visit(ctx.term(0));
            for (int i = 1; i < ctx.term().size(); i++) {
                String op = ctx.getChild(2*i - 1).getText();
                Double term = visit(ctx.term(i));
                if (op.equals('+')) {
                    result += term;
                } else {
                    result -= term;
                }
            }
            return result;
        }
    
        // 重写visitTerm身手,用于筹算乘法和除法
        @Override
        public Double visitTerm(ArithmeticParser.TermContext ctx) {
            Double result = visit(ctx.factor(0));
            for (int i = 1; i < ctx.factor().size(); i++) {
                String op = ctx.getChild(2*i - 1).getText();
                Double factor = visit(ctx.factor(i));
                if (op.equals('*')) {
                    result *= factor;
                } else {
                    result /= factor;
                }
            }
            return result;
        }
    
        // 重写visitFactor身手,用于筹算数字和括号内的抒发式
        @Override
        public Double visitFactor(ArithmeticParser.FactorContext ctx) {
            if (ctx.NUMBER() != null) {
                // 如果是一个数字,平直复返其值
                return Double.parseDouble(ctx.NUMBER().getText());
            } else {
                // 如果是括号内的抒发式,递归调用visit身手
                return visit(ctx.expr());
            }
        }
    }
    
    
    测试

    新建测试类Test.java

    public class Test {
    
            public static void main(String[] args) throws Exception {
                String input = '(1+2)*3-4';
                // 创建一个词法分析器,用于将输入养息为标记
                ArithmeticLexer lexer = new ArithmeticLexer(CharStreams.fromString(input));
    
                // 创建一个标记流,用于将标记传递给明白
                CommonTokenStream tokens = new CommonTokenStream(lexer);
    
                // 创建一个明白器,用于将标记养息为AST
                ArithmeticParser parser = new ArithmeticParser(tokens);
    
                // 调用明白器的parse身手,生成AST
                ParseTree tree = parser.parse();
    
                // 创建一个AST遍历器,用于筹算抒发式的值
                EvalVisitor eval = new EvalVisitor();
    
                // 遍历AST,并筹算抒发式的值
                double result = eval.visit(tree);
    
                // 打印筹算效果
                System.out.println(result);
        }
    
    }
    

    测试(1+2)*3-4效果如图:

    图片

    本站仅提供存储工作,通盘本色均由用户发布,如发现存害或侵权本色,请点击举报。

    TOP