最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot集成antlr實(shí)現(xiàn)詞法和語(yǔ)法分析

 更新時(shí)間:2024年06月13日 09:11:31   作者:HBLOG  
Antlr4 是一款強(qiáng)大的語(yǔ)法生成器工具,可用于讀取、處理、執(zhí)行和翻譯結(jié)構(gòu)化的文本或二進(jìn)制文件,基本上是當(dāng)前 Java 語(yǔ)言中使用最為廣泛的語(yǔ)法生成器工具,本文給大家介紹了SpringBoot集成antlr實(shí)現(xiàn)詞法和語(yǔ)法分析,需要的朋友可以參考下

1.什么是antlr?

Antlr4 是一款強(qiáng)大的語(yǔ)法生成器工具,可用于讀取、處理、執(zhí)行和翻譯結(jié)構(gòu)化的文本或二進(jìn)制文件。基本上是當(dāng)前 Java 語(yǔ)言中使用最為廣泛的語(yǔ)法生成器工具。Twitter搜索使用ANTLR進(jìn)行語(yǔ)法分析,每天處理超過(guò)20億次查詢;Hadoop生態(tài)系統(tǒng)中的Hive、Pig、數(shù)據(jù)倉(cāng)庫(kù)和分析系統(tǒng)所使用的語(yǔ)言都用到了ANTLR;Lex Machina將ANTLR用于分析法律文本;Oracle公司在SQL開(kāi)發(fā)者IDE和遷移工具中使用了ANTLR;NetBeans公司的IDE使用ANTLR來(lái)解析C++;Hibernate對(duì)象-關(guān)系映射框架(ORM)使用ANTLR來(lái)處理HQL語(yǔ)言

基本概念

語(yǔ)法分析器(parser)是用來(lái)識(shí)別語(yǔ)言的程序,本身包含兩個(gè)部分:詞法分析器(lexer)和語(yǔ)法分析器(parser)。詞法分析階段主要解決的關(guān)鍵詞以及各種標(biāo)識(shí)符,例如 INT、ID 等,語(yǔ)法分析主要是基于詞法分析的結(jié)果,構(gòu)造一顆語(yǔ)法分析樹(shù)。大致的流程如下圖參考2所示。

 因此,為了讓詞法分析和語(yǔ)法分析能夠正常工作,在使用 Antlr4 的時(shí)候,需要定義語(yǔ)法(grammar),這部分就是 Antlr 元語(yǔ)言。

使用 ANTLR4 編程的基本流程是固定的,通常分為如下三步:

  • 基于需求按照 ANTLR4 的規(guī)則編寫自定義語(yǔ)法的語(yǔ)義規(guī)則, 保存成以 g4 為后綴的文件。

  • 使用 ANTLR4 工具處理 g4 文件,生成詞法分析器、句法分析器代碼、詞典文件。

  • 編寫代碼繼承 Visitor 類或?qū)崿F(xiàn) Listener 接口,開(kāi)發(fā)自己的業(yè)務(wù)邏輯代碼。

Listener 模式和 Visitor 模式的區(qū)別

Listener 模式:

Visitor 模式:

  • Listener 模式通過(guò) walker 對(duì)象自行遍歷,不用考慮其語(yǔ)法樹(shù)上下級(jí)關(guān)系。Vistor 需要自行控制訪問(wèn)的子節(jié)點(diǎn),如果遺漏了某個(gè)子節(jié)點(diǎn),那么整個(gè)子節(jié)點(diǎn)都訪問(wèn)不到了。
  • Listener 模式的方法沒(méi)有返回值,Vistor 模式可以設(shè)定任意返回值。
  • Listener 模式的訪問(wèn)棧清晰明確,Vistor 模式是方法調(diào)用棧,如果實(shí)現(xiàn)出錯(cuò)有可能導(dǎo)致 StackOverFlow。

2.代碼工程

實(shí)驗(yàn)?zāi)康模簩?shí)現(xiàn)基于antlr的計(jì)算器

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springboot-demo</artifactId>
        <groupId>com.et</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>ANTLR</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <antlr4.version>4.9.1</antlr4.version>
    </properties>
    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.antlr</groupId>
            <artifactId>antlr4-runtime</artifactId>
            <version>${antlr4.version}</version>
        </dependency>

    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.antlr</groupId>
                <artifactId>antlr4-maven-plugin</artifactId>
                <version>${antlr4.version}</version>
                <configuration>
                    <sourceDirectory>src/main/java</sourceDirectory>
                    <outputDirectory>src/main/java</outputDirectory>
                    <arguments>
                        <argument>-visitor</argument>
                        <argument>-listener</argument>
                    </arguments>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>antlr4</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

元語(yǔ)言LabeledExpr.g4

grammar LabeledExpr; // rename to distinguish from Expr.g4

prog:   stat+ ;

stat:   expr NEWLINE                # printExpr
    |   ID '=' expr NEWLINE         # assign
    |   NEWLINE                     # blank
    ;

expr:   expr op=('*'|'/') expr      # MulDiv
    |   expr op=('+'|'-') expr      # AddSub
    |   INT                         # int
    |   ID                          # id
    |   '(' expr ')'                # parens
    ;

MUL :   '*' ; // assigns token name to '*' used above in grammar
DIV :   '/' ;
ADD :   '+' ;
SUB :   '-' ;
ID  :   [a-zA-Z]+ ;      // match identifiers
INT :   [0-9]+ ;         // match integers
NEWLINE:'\r'? '\n' ;     // return newlines to parser (is end-statement signal)
WS  :   [ \t]+ -> skip ; // toss out whitespace

簡(jiǎn)單解讀一下 LabeledExpr.g4 文件。ANTLR4 規(guī)則是基于正則表達(dá)式定義定義。規(guī)則的理解是自頂向下的,每個(gè)分號(hào)結(jié)束的語(yǔ)句表示一個(gè)規(guī)則 。例如第一行:grammar LabeledExpr; 表示我們的語(yǔ)法名稱是 LabeledExpr, 這個(gè)名字需要跟文件名需要保持一致。Java 編碼也有相似的規(guī)則:類名跟類文件一致。

  • 規(guī)則 prog 表示 prog 是一個(gè)或多個(gè) stat。
  • 規(guī)則 stat 適配三種子規(guī)則:空行、表達(dá)式 expr、賦值表達(dá)式 ID’=’expr。
  • 表達(dá)式 expr 適配五種子規(guī)則:乘除法、加減法、整型、ID、括號(hào)表達(dá)式。很顯然,這是一個(gè)遞歸的定義。

最后定義的是組成復(fù)合規(guī)則的基礎(chǔ)元素,比如:規(guī)則 **ID: [a-zA-Z]+**表示 ID 限于大小寫英文字符串;INT: [0-9]+; 表示 INT 這個(gè)規(guī)則是 0-9 之間的一個(gè)或多個(gè)數(shù)字,當(dāng)然這個(gè)定義其實(shí)并不嚴(yán)格。再嚴(yán)格一點(diǎn),應(yīng)該限制其長(zhǎng)度。

在理解正則表達(dá)式的基礎(chǔ)上,ANTLR4 的 g4 語(yǔ)法規(guī)則還是比較好理解的。

定義 ANTLR4 規(guī)則需要注意一種情況,即可能出現(xiàn)一個(gè)字符串同時(shí)支持多種規(guī)則,如以下的兩個(gè)規(guī)則:

ID: [a-zA-Z]+;

FROM: ‘from’;

很明顯,字符串” from”同時(shí)滿足上述兩個(gè)規(guī)則,ANTLR4 處理的方式是按照定義的順序決定。這里 ID 定義在 FROM 前面,所以字符串 from 會(huì)優(yōu)先匹配到 ID 這個(gè)規(guī)則上。

其實(shí)在定義好與法規(guī)中,編寫完成 g4 文件后,ANTLR4 已經(jīng)為我們完成了 50%的工作:幫我們實(shí)現(xiàn)了整個(gè)架構(gòu)及接口了,剩下的開(kāi)發(fā)工作就是基于接口或抽象類進(jìn)行具體的實(shí)現(xiàn)。實(shí)現(xiàn)上有兩種方式來(lái)處理生成的語(yǔ)法樹(shù),其一 Visitor 模式,另一種方式是 Listener(監(jiān)聽(tīng)器模式)。

生成詞法和語(yǔ)法解析器

基于maven插件生成

<plugin>
    <groupId>org.antlr</groupId>
    <artifactId>antlr4-maven-plugin</artifactId>
    <version>${antlr4.version}</version>
    <configuration>
        <sourceDirectory>src/main/java</sourceDirectory>
        <outputDirectory>src/main/java</outputDirectory>
        <arguments>
            <argument>-visitor</argument>
            <argument>-listener</argument>
        </arguments>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>antlr4</goal>
            </goals>
        </execution>
    </executions>
</plugin>

執(zhí)行命令

mvn antlr4:antlr4

使用ideal插件生成

實(shí)現(xiàn)運(yùn)算邏輯

第一種:基于visitor實(shí)現(xiàn)

package com.et.antlr;

import java.util.HashMap;
import java.util.Map;

public class EvalVisitor extends LabeledExprBaseVisitor<Integer> {
    // Store variables (for assignment)
    Map<String, Integer> memory = new HashMap<>();

    /** stat : expr NEWLINE */
    @Override
    public Integer visitPrintExpr(LabeledExprParser.PrintExprContext ctx) {
        Integer value = visit(ctx.expr()); // evaluate the expr child
       // System.out.println(value);         // print the result
        return value;                          // return dummy value
    }

    /** stat : ID '=' expr NEWLINE */
    @Override
    public Integer visitAssign(LabeledExprParser.AssignContext ctx) {
        String id = ctx.ID().getText(); // id is left-hand side of '='
        int value = visit(ctx.expr());  // compute value of expression on right
        memory.put(id, value);          // store it in our memory
        return value;
    }

    /** expr : expr op=('*'|'/') expr */
    @Override
    public Integer visitMulDiv(LabeledExprParser.MulDivContext ctx) {
        int left = visit(ctx.expr(0));  // get value of left subexpression
        int right = visit(ctx.expr(1)); // get value of right subexpression
        if (ctx.op.getType() == LabeledExprParser.MUL) return left * right;
        return left / right; // must be DIV
    }

    /** expr : expr op=('+'|'-') expr */
    @Override
    public Integer visitAddSub(LabeledExprParser.AddSubContext ctx) {
        int left = visit(ctx.expr(0));  // get value of left subexpression
        int right = visit(ctx.expr(1)); // get value of right subexpression
        if (ctx.op.getType() == LabeledExprParser.ADD) return left + right;
        return left - right; // must be SUB
    }

    /** expr : INT */
    @Override
    public Integer visitInt(LabeledExprParser.IntContext ctx) {
        return Integer.valueOf(ctx.INT().getText());
    }

    /** expr : ID */
    @Override
    public Integer visitId(LabeledExprParser.IdContext ctx) {
        String id = ctx.ID().getText();
        if (memory.containsKey(id)) return memory.get(id);
        return 0; // default value if the variable is not found
    }

    /** expr : '(' expr ')' */
    @Override
    public Integer visitParens(LabeledExprParser.ParensContext ctx) {
        return visit(ctx.expr()); // return child expr's value
    }

    /** stat : NEWLINE */
    @Override
    public Integer visitBlank(LabeledExprParser.BlankContext ctx) {
        return 0; // return dummy value
    }
}

第二種:基于listener實(shí)現(xiàn)

package com.et.antlr;

import org.antlr.v4.runtime.tree.ParseTreeProperty;
import org.antlr.v4.runtime.tree.TerminalNode;

import java.util.HashMap;
import java.util.Map;

public class EvalListener extends LabeledExprBaseListener {
    // Store variables (for assignment)
    private final Map<String, Integer> memory = new HashMap<>();
    // Store expression results
    private final ParseTreeProperty<Integer> values = new ParseTreeProperty<>();
    private int result=0;
    @Override
    public void exitPrintExpr(LabeledExprParser.PrintExprContext ctx) {
        int value = values.get(ctx.expr());
        //System.out.println(value);
        result=value;
    }
    public int getResult() {
       return result;
    }
    @Override
    public void exitAssign(LabeledExprParser.AssignContext ctx) {
        String id = ctx.ID().getText();
        int value = values.get(ctx.expr());
        memory.put(id, value);
    }

    @Override
    public void exitMulDiv(LabeledExprParser.MulDivContext ctx) {
        int left = values.get(ctx.expr(0));
        int right = values.get(ctx.expr(1));
        if (ctx.op.getType() == LabeledExprParser.MUL) {
            values.put(ctx, left * right);
        } else {
            values.put(ctx, left / right);
        }
    }

    @Override
    public void exitAddSub(LabeledExprParser.AddSubContext ctx) {
        int left = values.get(ctx.expr(0));
        int right = values.get(ctx.expr(1));
        if (ctx.op.getType() == LabeledExprParser.ADD) {
            values.put(ctx, left + right);
        } else {
            values.put(ctx, left - right);
        }

    }

    @Override
    public void exitInt(LabeledExprParser.IntContext ctx) {
        int value = Integer.parseInt(ctx.INT().getText());
        values.put(ctx, value);
    }

    @Override
    public void exitId(LabeledExprParser.IdContext ctx) {
        String id = ctx.ID().getText();
        if (memory.containsKey(id)) {
            values.put(ctx, memory.get(id));
        } else {
            values.put(ctx, 0); // default value if the variable is not found
        }
    }

    @Override
    public void exitParens(LabeledExprParser.ParensContext ctx) {
        values.put(ctx, values.get(ctx.expr()));
    }
}

以上只是一些關(guān)鍵代碼,所有代碼請(qǐng)參見(jiàn)下面代碼倉(cāng)庫(kù)

代碼倉(cāng)庫(kù)

3.測(cè)試

測(cè)試vistor方式

package com.et.antlr; /***
 * Excerpted from "The Definitive ANTLR 4 Reference",
 * published by The Pragmatic Bookshelf.
 * Copyrights apply to this code. It may not be used to create training material, 
 * courses, books, articles, and the like. Contact us if you are in doubt.
 * We make no guarantees that this code is fit for any purpose. 
 * Visit http://www.pragmaticprogrammer.com/titles/tpantlr2 for more book information.
***/
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.ParseTree;

import java.io.FileInputStream;
import java.io.InputStream;

public class CalcByVisit {
    public static void main(String[] args) throws Exception {
     /*   String inputFile = null;
        if ( args.length>0 ) inputFile = args[0];
        InputStream is = System.in;
        if ( inputFile!=null ) is = new FileInputStream(inputFile);*/
        ANTLRInputStream input = new ANTLRInputStream("1+2*3\n");
        LabeledExprLexer lexer = new LabeledExprLexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        LabeledExprParser parser = new LabeledExprParser(tokens);
        ParseTree tree = parser.prog(); // parse

        EvalVisitor eval = new EvalVisitor();
        int result =eval.visit(tree);
        System.out.println(result);
    }
}

測(cè)試listener方式

package com.et.antlr;

import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * @author liuhaihua
 * @version 1.0
 * @ClassName CalbyLisenter
 * @Description todo
 * @date 2024年06月06日 16:40
 */

public class CalbyLisener {
    public static void main(String[] args) throws IOException {
      /*  String inputFile = null;
        if ( args.length>0 ) inputFile = args[0];
        InputStream is = System.in;
        if ( inputFile!=null ) is = new FileInputStream(inputFile);*/
        ANTLRInputStream input = new ANTLRInputStream("1+2*3\n");
        LabeledExprLexer lexer = new LabeledExprLexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        LabeledExprParser parser = new LabeledExprParser(tokens);
        ParseTree tree = parser.prog(); // parse

        ParseTreeWalker walker = new ParseTreeWalker();
        EvalListener evalListener =new EvalListener();
        walker.walk(evalListener, tree);
        int result=evalListener.getResult();
        System.out.println(result);
    }
}

運(yùn)行上述測(cè)試用例,計(jì)算結(jié)果符合預(yù)期

4.引用

https://www.antlr.org/

以上就是SpringBoot集成antlr實(shí)現(xiàn)詞法和語(yǔ)法分析的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot antlr詞法和語(yǔ)法分析的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java 8 Stream操作類型及peek示例解析

    Java 8 Stream操作類型及peek示例解析

    這篇文章主要介紹了Java 8 Stream操作類型及peek示例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • Spring?DI依賴注入過(guò)程解析

    Spring?DI依賴注入過(guò)程解析

    依賴注入是由“依賴”和“注入”兩個(gè)詞匯組合而成,那么我們?cè)僖淮雾樚倜希謩e分析這兩個(gè)詞語(yǔ),這篇文章主要介紹了Spring?DI依賴注入詳解,需要的朋友可以參考下
    2022-11-11
  • 對(duì)handlerexecutionchain類的深入理解

    對(duì)handlerexecutionchain類的深入理解

    下面小編就為大家?guī)?lái)一篇對(duì)handlerexecutionchain類的深入理解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-07-07
  • 微信跳一跳輔助Java代碼實(shí)現(xiàn)

    微信跳一跳輔助Java代碼實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了微信跳一跳輔助的Java代碼實(shí)現(xiàn)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • Java從零編寫汽車租賃系統(tǒng)全程分析

    Java從零編寫汽車租賃系統(tǒng)全程分析

    這篇文章介紹了Java實(shí)現(xiàn)汽車租賃系統(tǒng)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-12-12
  • MyBatisPlus自定義JsonTypeHandler實(shí)現(xiàn)自動(dòng)轉(zhuǎn)化JSON問(wèn)題

    MyBatisPlus自定義JsonTypeHandler實(shí)現(xiàn)自動(dòng)轉(zhuǎn)化JSON問(wèn)題

    這篇文章主要介紹了MyBatisPlus自定義JsonTypeHandler實(shí)現(xiàn)自動(dòng)轉(zhuǎn)化JSON問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • java實(shí)現(xiàn)簡(jiǎn)單的拼圖游戲

    java實(shí)現(xiàn)簡(jiǎn)單的拼圖游戲

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)單的拼圖游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • Java設(shè)計(jì)模塊系列之書(shū)店管理系統(tǒng)單機(jī)版(二)

    Java設(shè)計(jì)模塊系列之書(shū)店管理系統(tǒng)單機(jī)版(二)

    這篇文章主要為大家詳細(xì)介紹了Java單機(jī)版的書(shū)店管理系統(tǒng)設(shè)計(jì)模塊和思想第二章,感興趣的小伙伴們可以參考一下
    2016-08-08
  • Java超詳細(xì)講解設(shè)計(jì)模式中的命令模式

    Java超詳細(xì)講解設(shè)計(jì)模式中的命令模式

    命令模式是將一個(gè)請(qǐng)求封裝為一個(gè)對(duì)象,從而可用不同的請(qǐng)求對(duì)客戶進(jìn)行參數(shù)化,對(duì)請(qǐng)求排隊(duì)或者對(duì)請(qǐng)求做日志記錄,以及可以支持撤銷的操作
    2022-04-04
  • Spring Boot3 集成 Spring AI 實(shí)現(xiàn) Advisor 增強(qiáng)機(jī)制的完整流程

    Spring Boot3 集成 Spring AI 實(shí)現(xiàn) A

    Spring AI的Advisor API是一種聲明式的攔截機(jī)制,借鑒了 Spring AOP 的設(shè)計(jì)理念,允許開(kāi)發(fā)者在AI交互的生命周期關(guān)鍵節(jié)點(diǎn)插入自定義邏輯,本文全面介紹了Spring Boot集成Spring AI 1.0.0 實(shí)現(xiàn) Advisor 增強(qiáng)機(jī)制的完整流程,感興趣的朋友跟隨小編一起看看吧
    2026-03-03

最新評(píng)論

裕民县| 航空| 阆中市| 叙永县| 泸西县| 城步| 岱山县| 资阳市| 北海市| 景德镇市| 安达市| 定襄县| 南华县| 曲沃县| 霍邱县| 铜川市| 旬阳县| 桂阳县| 永靖县| 武强县| 喀喇沁旗| 信宜市| 乐山市| 松滋市| 阳山县| 教育| 大余县| 林西县| 涿鹿县| 璧山县| 高安市| 鄢陵县| 铁力市| 渭南市| 崇明县| 雷波县| 石嘴山市| 洪泽县| 库车县| 武汉市| 嵊州市|