JavaCC從入門到出門

来源:http://www.cnblogs.com/orlion/archive/2017/06/29/7096645.html
-Advertisement-
Play Games

一、JavaCC JavaCC是java的compiler compiler。JavaCC是LL解析器生成器,可處理的語法範圍比較狹窄,但支持無限長的token超前掃描。 安裝過程: 我是從github上down下來的zip壓縮包,然後安裝了下ant, 然後通過ant安裝的javacc 1. 首先下 ...


一、JavaCC

  JavaCC是java的compiler compiler。JavaCC是LL解析器生成器,可處理的語法範圍比較狹窄,但支持無限長的token超前掃描。

  安裝過程:

  我是從github上down下來的zip壓縮包,然後安裝了下ant, 然後通過ant安裝的javacc

  1. 首先下載下來ant的源碼,然後tar -zvxf apache-ant....tag.gz 解壓縮,然後可以在解壓出來的bin目錄中看到ant的可執行文件

  2. 從github下載javacc, 進入解壓縮的目錄執行xxxxxx/ant。 然後會在target 目錄中看到javacc.jar 包

  3. 這個時候可以通過如下方法將jar包做成一個可執行文件:

    首先創建一個shell腳本:

#!/bin/sh
MYSELF=`which "$0" 2>/dev/null`
[ $? -gt 0 -a -f "$0" ] && MYSELF="./$0"
java=java
if test -n "$JAVA_HOME"; then
    java="$JAVA_HOME/bin/java"
fi
exec "$java" $java_args -cp $MYSELF "$@"
exit 1

    命名為stub.sh, 然後在jar包的所在目錄執行: cat stub.sh javacc.jar > javacc && chmod +x javacc。 這樣一個可執行文件就有了,不過在解析.jj文件時需要帶一個javacc的參數,像這樣: javacc javacc Adder.jj

二、語法描述文件

1、簡介

  JavaCC的語法描述文件是擴展名為.jj的文件,一般情況下,語法描述文件的內容採用如下形式

options {
    JavaCC的選項
}

PARSER_BEGIN(解析器類名)
package 包名;
import 庫名;

public class 解析器類名 {
    任意的Java代碼
}
PARSER_END(解析器類名)

掃描器的描述

解析器的描述

  JavaCC和java一樣將解析器的內容定義在單個類中,因此會在PARSER_BEGIN和PARSER_END之間描述這個類的相關內容。

2、Example

  如下代碼是一個解析正整數加法運算併進行計算的解析器的語法描述文件。

options {
    STATIC = false;
}

PARSER_BEGIN(Adder)
import java.io.*;

class Adder {
    public static void main(String[] args) {
        for (String arg : args) {
            try {
                System.out.println(evaluate(arg));
            } catch (ParseException ex) {
                System.err.println(ex.getMessage());
            }
        }
    }
    
    public static long evaluate(String src) throws ParseException {
        Reader reader = new StringReader(src);
        return new Adder(reader).expr();
    }
}
PARSER_END(Adder)

SKIP: { <[" ", "\t", "\r", "\n"]> }

TOKEN: {
    <INTEGER: (["0"-"9"])+>
}

long expr():
{
    Token x, y;
}
{
    x=<INTEGER> "+" y=<INTEGER> <EOF>
    {
        return Long.parseLong(x.image) + Long.parseLong(y.image);
    }
}

  options塊中將STATIC選項設置為false, 將該選項設置為true的話JavaCC生成的所有成員及方法都將被定義為static,若將STATIC設置為true則所生成的解析器無法在多線程環境下使用,因此該選項總是被設置為false。(STATIC的預設值為true)
  從PARSER_BEING(Adder)到PARSER_END(Adder)是解析器類的定義。解析器類中需要定義的成員和方法也寫在這裡。為了實現即使只有Adder類也能夠運行,這裡定義了main函數。
  之後的SKIP和TOKEN部分定義了掃描器。SKIP表示要跳過空格、製表符(tab)和換行符。TOKEN表示掃描整數字元並生成token。
  long expr...開始到最後的部分定義了狹義的解析器。這部分解析token序列並執行某些操作。

3、運行JavaCC

  要用JavaCC來處理Adder.jj(圖中是demo1.jj),需要使用如下javacc命令

  運行如上命令會生成Adder.java和其他輔助類。
  要編譯生成的Adder.java,只需要javac命令即可:

 

這樣就生成了Adder.class文件。Adder類是從命令行參數獲取計算式併進行計算的,因此可以如下這樣從命令行輸入計算式並執行

 

三、啟動JavaCC生成的解析器

  現在解析一下main函數的代碼。   main函數將所有命令行參數的字元串作為計算對象的算式,依次用evaluate方法進行計算。
  evaluate方法中生成了Adder類的對象實例 。並讓Adder對象來計算(解析)參數字元串src。
  要運行JavaCC生成的解析器類,需要下麵2個步驟:

  1. 生成解析器類的對象實例
  2. 用生成的對象調用和需要解析的語句同名的方法

  第1點: JavaCC4.0生成的解析器中預設定義有如下四種類型的構造函數。

  1. Parser(InputStream s)
  2. Parser(InputStream s, String encoding)
  3. Parser(Reader r)
  4. Parser(x x x x TokenManager tm)

  第1種的構造函數是通過傳入InputStream對象來構造解析的。這個構造函數無法設定輸入字元串的編碼,因此無法處理中文字元等。
  而地2種的構造函數除了InputStream對象外,還可以設置輸入字元串的編碼來生成解析器。但如果要解析中文字元串或註釋的話,就必須使用第2種/3種構造函數。
  第3種的構造函數用於解析Reader對象所讀入的內容。
  第4種是將掃描器作為參數傳入。
  解析器生成後,用這個實例調用和需要解析的語法同名的方法。這裡調用Adder對象的expr方法,接回開始解析,解析正常結束後會返回語義值。

四、中文的處理

  要使JavaCC能夠處理中文首先需要將語法描述文件的options快的UNICODE_INPUT選項設置為true:

options {
    STATUS = false;
    DEBUG_PARSER = true;
    UNICODE_PARSER = true;
    JDK_VERSION = "1.5";
}

  這樣就會先將輸入的字元轉換成UNICODE後再進行處理。UNICODE_INPUT選項為false時只能處理ASCII範圍的字元。
  另外還需要使用第2/3種構造方法為輸入的字元串設置適當的編碼。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在mvvm模式的wpf項目中有個需求需要去載入解決方案的程式集,並且根據程式集去動態載入當前程式集的類,做成下拉框形式。 效果: wpf窗體: ...
  • 本期來討論下,jupyter notebook中怎樣同時安裝python2.7 和python3.x。 ...
  • 介面是什麼,抽象類又是什麼,有了抽象類,我們為什麼還要有介面呢? 抽象類 抽象類的概念: 抽象類是相對於普通類而言的,普通類是一個完善的功能類,可以直接產生實例化對象,並且在普通類中可以包含有構造方法、普通方法、static方法、常量和變數等內容。而抽象類是指在普通類的結構裡面增加抽象方法的組成部分 ...
  • 一、說明 與@Component註解功能相同,但意義不同的註解還有三個: 1)@Repository:註解在Dao實現類上 2)@Service:註解在Service實現類上 3)@Controller:註解在SpringMVC的處理器上 Bean作用域: @Scope("prototype"):用 ...
  • Python中的可變對象和不可變對象 什麼是可變/不可變對象 不可變對象,該對象所指向的記憶體中的值不能被改變。 當改變某個變數時候,由於其所指的值不能被改變,相當於把原來的值複製一份後再改變,這會開闢一個新的地址,變數再指向這個新的地址。 可變對象,該對象所指向的記憶體中的值可以被改變。 變數(準確的 ...
  • /* 選擇工廠和更新工廠模式,這個模式的類(UpdateFactory和SelectionFactory類)就是用來創建SQL語句的. 因為涉及到之前學習的內容比較多,這裡就儘量將之前相關模式的示例代碼放在一起來進行學習和回顧了。 以下的代碼都是代碼片段而且涉及到連接資料庫,無法進行整體的調試(某些... ...
  • 動態規劃的演算法題往往都是各大公司筆試題的常客。在不少演算法類的微信公眾號中,關於“動態規劃”的文章屢見不鮮,都在試圖用最淺顯易懂的文字來描述講解動態規劃,甚至有的用漫畫來解釋,認真讀每一篇公眾號推送的文章實際上都能讀得懂,都能對動態規劃有一個大概瞭解。 什麼是動態規劃?通俗地理解來說,一個問題的解決辦 ...
  • 這是我寫的登陸註冊界面,使用tkinter,可以實現簡單的登陸和註冊賬號,使用的主要是Label,Entry和Button組件。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...