1. 程式人生 > >Graduation Project——設計語法分析器

Graduation Project——設計語法分析器

文法定義

primary: "("expr")"|NUMBER|IDENTIFIER|STRING
factor:"-"primary|primary
expr:factor{OP factor}
block:"{"[statement]{(";"|EOL)[statement]}"}"
simple:expr
statement:"if" expr block["else" block]
	|"while" expr block
	|simple
	|"rhy" problock
problock:"{"[music]{(";"|EOL)music}"}"
music:"sn"|"fl"|"hi"|"bi"|"sm"|"ki"|"cr"
program:[statement](";"|EOL)

進一步的語法待定。

使用解析器和組合子

package stone;

import java.util.HashSet;
import static stone.Parser.rule;
import stone.Parser.Operators;
import stone.ast.*;
import stone.token.Token;

public class BasicParser {
     /*
    primary: "("expr")"|NUMBER|IDENTIFIER|STRING
    factor:"-"primary|primary
    expr:factor{OP factor}
    block:"{"[statement]{(";"|EOL)[statement]}"}"
    simple:expr
    statement:"if" expr block["else" block]
	    |"while" expr block
	    |simple
	    |"rhy" problock
    problock:"{"[music]{(";"|EOL)music}"}"
    music:"sn"|"fl"|"hi"|"bi"|"sm"|"ki"|"cr"
    program:[statement](";"|EOL)
     */
/* *首先定義了大量Parser型別的欄位,他們是將程式碼的BNF規則轉換為java語言的結果。 */ protected HashSet<String> reserved=new HashSet<>(); Operators operators=new Operators(); Parser expr0=rule(); // primary: "("expr")"|NUMBER|IDENTIFIER|STRING Parser primary=rule(PrimaryExpr.class) .
or(rule().sep("(").ast(expr0).sep(")"), rule().number(NumberLiteral.class), rule().identifier(Name.class,reserved), rule().string(StringLiteral.class)); //factor:"-"primary|primary Parser factor =rule().or(rule(NegativeExpr.class).sep("-").ast(primary),primary); //expr:factor{OP factor} protected Parser expr=expr0.expression(BinaryExpr.class,factor,operators); Parser statement0=rule(); // block:"{"[statement]{(";"|EOL)[statement]}"}" protected Parser block=rule(BlockStmnt.class) .sep("{").option(statement0) .repeat(rule().sep(";", Token.EOL).option(statement0)) .sep("}"); // simple:expr Parser simple=rule(PrimaryExpr.class).ast(expr); // music:"sn"|"fl"|"hi"|"bi"|"sm"|"ki"|"cr" Parser music=rule().or( rule().token("cr"), rule().token("sn"), rule().token("fl"), rule().token("hi"), rule().token("bi"), rule().token("sm"), rule().token("ki")); // problock:"{"{[music](";"|EOL)}"}" Parser problock=rule(ProblockStmnt.class).sep("{").repeat(rule().option(music).sep(";", Token.EOL)).sep("}"); /* statement:"if" expr block["else" block] |"while" expr block |simple |"rhy" problock */ protected Parser statement=statement0.or( rule(IfStmnt.class).sep("if").ast(expr).ast(block) .option(rule().sep("else").ast(block)), rule(WhileStmnt.class).sep("while").ast(expr).ast(block), rule(RhyStmnt.class).sep("rhy") .token("{").option(rule().token(Token.EOL)) .ast(music) .repeat(rule().token(";", Token.EOL) .option(music)) .option(rule().token(";",Token.EOL)).token("}"), simple ); Parser program=rule().or(statement,rule(NULLStmnt.class)).sep(";",Token.EOL); public BasicParser(){ reserved.add(";"); reserved.add("}"); reserved.add(Token.EOL); operators.add("=",1,Operators.RIGHT); operators.add("==",2,Operators.LEFT); operators.add(">",2,Operators.LEFT); operators.add("<",2,Operators.LEFT); operators.add("+",2,Operators.LEFT); operators.add("-",2,Operators.LEFT); operators.add("*",2,Operators.LEFT); operators.add("/",2,Operators.LEFT); operators.add("%",2,Operators.LEFT); } public ASTree parse(Lexer lexer){ return program.parse(lexer); } }

我們先來解釋一下BasicParser類,它是通過Parser類,將java程式碼來替代和解釋BNF規則,比如:
factor:"-"primary|primary
可以被解釋為:
Parser factor =rule().or(rule(NegativeExpr.class).sep("-").ast(primary),primary);
所以這個類很好理解,重點在於什麼呢?
rule方法和其中的sep、ast等方法。
我們先來看看Parser:

package stone;


import stone.Exception.ParseException;
import stone.ast.ASTLeaf;
import stone.ast.ASTList;
import stone.ast.ASTree;
import stone.token.Token;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;

/**
 * Parser庫的工作是將BNF寫成的語法規則改寫為Java語言程式
 * rule()方法是Parser類的一個static方法
 */
public class Parser {
    protected static abstract class Element {
        protected abstract void parse(Lexer lexer, List<ASTree> res)
                throws ParseException;
        protected abstract boolean match(Lexer lexer) throws ParseException;
    }

    protected static class Tree extends Element {
        protected Parser parser;
        protected Tree(Parser p) { parser = p; }
        protected void parse(Lexer lexer, List<ASTree> res)
                throws ParseException
        {
            res.add(parser.parse(lexer));
        }
        protected boolean match(Lexer lexer) throws ParseException {
            return parser.match(lexer);
        }
    }

    protected static class OrTree extends Element {
        protected Parser[] parsers;
        protected OrTree(Parser[] p) { parsers = p; }
        protected void parse(Lexer lexer, List<ASTree> res)
                throws ParseException
        {
            Parser p = choose(lexer);
            if (p == null)
                throw new ParseException(lexer.peek(0));
            else
                res.add(p.parse(lexer));
        }
        protected boolean match(Lexer lexer) throws ParseException {
            return choose(lexer) != null;
        }
        protected Parser choose(Lexer lexer) throws ParseException {
            for (Parser p: parsers)
                if (p.match(lexer))
                    return p;

            return null;
        }
        protected void insert(Parser p) {
            Parser[] newParsers = new Parser[parsers.length + 1];
            newParsers[0] = p;
            System.arraycopy(parsers, 0, newParsers, 1, parsers.length);
            parsers = newParsers;
        }
    }

    protected static class Repeat extends Element {
        protected Parser parser;
        protected boolean onlyOnce;
        protected Repeat(Parser p, boolean once) { parser = p; onlyOnce = once; }
        protected void parse(Lexer lexer, List<ASTree> res)
                throws ParseException
        {
            while (parser.match(lexer)) {
                ASTree t = parser.parse(lexer);
                if (t.getClass() != ASTList.class || t.numChildren() > 0)
                    res.add(t);
                if (onlyOnce)
                    break;
            }
        }
        protected boolean match(Lexer lexer) throws ParseException {
            return parser.match(lexer);
        }
    }

    protected static abstract class AToken extends Element {
        protected Factory factory;
        protected AToken(Class<? extends ASTLeaf> type) {
            if (type == null)
                type = ASTLeaf.class;
            factory = Factory.get(type, Token.class);
        }
        protected void parse(Lexer lexer, List<ASTree> res)
                throws ParseException
        {
            Token t = lexer.read();
            if (test(t)) {
                ASTree leaf = factory.make(t);
                res.add(leaf);
            }
            else
                throw new ParseException(t);
        }
        protected boolean match(Lexer lexer) throws ParseException {
            return test(lexer.peek(0));
        }
        protected abstract boolean test(Token t);
    }

    protected static class IdToken extends AToken {
        HashSet<String> reserved;
        protected IdToken(Class<? extends ASTLeaf> type, HashSet<String> r) {
            super(type);
            reserved = r != null ? r : new HashSet<String>();
        }
        protected boolean test(Token t) {
            return t.isIdentifier() && !reserved.contains(t.getText());
        }
    }

    protected static class NumToken extends AToken {
        protected NumToken(Class<? extends ASTLeaf> type) { super(type); }
        protected boolean test(Token t) { return t.isNumber(); }
    }

    protected static class StrToken extends AToken {
        protected StrToken(Class<? extends ASTLeaf> type) { super(type); }
        protected boolean test(Token t) { return t.isString(); }
    }

    protected static class Leaf extends Element {
        protected String[] tokens;
        protected Leaf(String[] pat) { tokens = pat; }
        protected void parse(Lexer lexer, List<ASTree> res)
                throws ParseException
        {
            Token t = lexer.read();
            if (t.isIdentifier())
                for (String token: tokens)
                    if (token.equals(t.getText())) {
                        find(res, t);
                        return;
                    }

            if (tokens.length > 0)
                throw new ParseException(tokens[0] + " expected.", t);
            else
                throw new ParseException(t);
        }
        protected void find(List<ASTree> res, Token t) {
            res.add(new ASTLeaf(t));
        }
        protected boolean match(Lexer lexer) throws ParseException {
            Token t = lexer.peek(0);
            if (t.isIdentifier())
                for (String token: tokens)
                    if (token.equals(t.getText()))
                        return true;

            return false;
        }
    }

    protected static class Skip extends Leaf {
        protected Skip(String[] t) { super(t); }
        protected void find(List<ASTree> res, Token t) {}
    }

    public static class Precedence {
        int value;
        boolean leftAssoc; // left associative
        public Precedence(int v, boolean a) {
            value = v; leftAssoc = a;
        }
    }

    public static class Operators extends HashMap<String,Precedence> {
        private static final long serialVersionUID = 1580735370084704878L;
        public static boolean LEFT = true;
        public static boolean RIGHT = 
            
           

相關推薦

Graduation Project——設計語法分析器

文法定義 primary: "("expr")"|NUMBER|IDENTIFIER|STRING factor:"-"primary|primary expr:factor{OP factor} block:"{"[statement]{(";"|EOL)[statement]}"}"

Graduation Project——設計程式設計語言

整理我們的需求 首先這是一個針對架子鼓的編譯器,架子鼓有7個組成部分,比如bass drum、snare drum等等。使用者能夠根據指令碼程式碼來呼叫這幾個鼔的打擊。 而打擊也分為節奏,使用者指定一個BPM來指定節奏的快慢,預設為60bpm。 當然也分節拍,預設60

用子程式呼叫法設計語法分析器

對每個非終極符按其產生式結構產生相應語法分析子程式. 其中: 1,終極符產生匹配命令 2,非終極符則產生呼叫命令 實驗用例: Z → a B a B → b B| c import java.util.*; public class ReadToken { pr

Graduation Project——詞法分析器

語言處理器的第一個組成部分是詞法分析器(lexer),也叫scanner。程式的原始碼最初是一長串字串。從內部來看,原始碼中的換行也能用專門的(不可見)換行符表示。所以這一長串程式碼會首先被處理為一個一個的token,也成為token流。 token流 譬如下面這一行程式碼: whi

ready!Go(Graduation Project)

關於 har 鎖定 聯網 fix 信任 詳情 上線 開發 1.球員動態不顯示下線問答 在局域網下配置WiFi代理設置 手動配置 ,打開API,利用抓包工具Charles(charles設置問題,亂碼等。https顯示unknow,手機無法聯網需要在手機端的 關於本機==&

【編譯原理】c++實現自下而上語法分析器

不可 acm times style size PC -i 表達式 鏈接 寫在前面:本博客為本人原創,嚴禁任何形式的轉載!本博客只允許放在博客園(.cnblogs.com),如果您在其他網站看到這篇博文,請通過下面這個唯一的合法鏈接轉到原文! 本博客全網唯一合法URL:ht

編譯原理實驗二:LL(1)語法分析器

處理 字符 編號 析構 idt public 輸入 課本 字母 一、實驗要求      不得不想吐槽一下編譯原理的實驗代碼量實在是太大了,是編譯原理撐起了我大學四年的代碼量...   這次實驗比上次要復雜得多,涵蓋的功能也更多了,我覺得這次實驗主要的難點有兩個(其實都是難點

編譯原理實驗 —— 語法分析器

/* 待分析的簡單語言的語法 用擴充的BNF表示如下: ⑴<程式>::=begin<語句串>end ⑵<語句串>::=<語句>{;<語句>} ⑶<語句>::=<賦值語句> ⑷<賦值語句>::=ID:=<

LeetCode385. 迷你語法分析器(Mini P)

題目描述 給定一個用字串表示的整數的巢狀列表,實現一個解析它的語法分析器。 列表中的每個元素只可能是整數或整數巢狀列表 提示: 你可以假定這些字串都是格式良好的: 字串非空 字串不包含空格 字串只包含數字0-9 [ - , ] 示例 1: 給定 s = "324", 你應該返回一

Graduation Project——編譯器初想

序言 我的畢設是做一個編譯器型別的音樂遊戲,基於SSM架構。由於前端製作水平和美術功底的限制,我只能靠著別人的網頁模版來製作。 現在前端大致已經制作的差不多,後端框架和環境已經搭好。萬事俱備,只欠東風——核心演算法。 關於核心演算法,之前也想了很多,但是萬事都要踏踏實實的來做,所以我打算

℃江的觀後感--語法分析器、語義分析器和程式碼生成器總結

其實javac在進行這些個什麼器的實現都是由一些類生成。這裡做一個總結,方便日後檢視吧。 語法分析器 我記得前面是說過詞法分析器這個東西的,其作用也很直觀,就是將Java原始檔的字元流轉換成對應的Token流,我們我們所謂規範化程式碼程式,讓其將人能看懂的

語法分析器(二) 識別多錯誤 Java版

 在上次實驗的基礎上進行改進,能夠識別多個錯誤,本文的只進行了部分資料的測試,所以可能會有其他錯誤識別不出來 部分缺失的程式碼請參考我之前寫的部落格,可以檢視完整的程式碼 package codescanner; import java.util.ArrayList;

385.迷你語法分析器

給定一個用字串表示的整數的巢狀列表,實現一個解析它的語法分析器。 列表中的每個元素只可能是整數或整數巢狀列表 提示:你可以假定這些字串都是格式良好的: 字串非空 字串不包含空格 字串只包含數字0-9, [, - ,, ] 示例 1: 給定 s = "324",

java編譯器原始碼分析之語法分析器

token流到抽象語法樹的過程是語法分析。 前面認識到token流,這部分將介紹抽象語法樹(AST)。 那麼什麼是抽象語法樹(AST)?AST長啥樣?我們的token流是如何轉變成AST的?下面圍繞這三個問題展開討論。 針對什麼是抽象語法樹以及語法樹長啥樣兩個問

三、語法分析器構造原理【待更】

一、自頂向下分析(top-down parsing) 1.自頂向下構造分析樹一般方法: 採用最左推導方式,總選擇句型中最左非終結符進行替換,替換時根據輸入流的下一個終結符選擇一個候選式。自頂向下構造方法可能引起回溯操作因此需要一定文法規則支援來避免回溯(即消除公共字首),

可配置語法分析器開發紀事(五)——構造一個真正能用的狀態機(中)

上一篇部落格寫到了如何給一個非終結符的文法規則構造出一個壓縮過的下推狀態機,那麼今天說的就是如何把所有的文法都連線起來。其實主要的idea在(三)和他的勘誤(三點五)裡面已經說得差不多了。但是今天我們要處理的是帶資訊的transition,所以還有一些地方要注意一下。 所以在這裡我們先把幾條文法

可配置語法分析器開發紀事(六)——構造一個真正能用的狀態機(下)

上一篇文章對大部分文法都構造出了一個使用的狀態機了,這次主要來講右遞迴的情況。右遞迴不像左遞迴那麼麻煩,因為大部分右遞迴寫成迴圈也不會過分的讓語法樹變得難以操作,不過仍然有少數情況是我們仍然希望保留遞迴的語法樹形狀,譬如C++的連等操作,因此這裡就來講一下這個問題。 右遞迴是怎麼形成的呢?在這裡我

可配置語法分析器開發紀事(三點五)——生成下推自動機的具體步驟

剛剛發了上一篇文章之後就發現狀態機畫錯了。雖然LiveWriter有開啟部落格並修改文章的功能,不過為了讓我留下一個教訓,我還是決定發一篇勘誤。這個教訓就是,作分析的時候不要隨便“跳步”,該一步一步來就一步一步來。其實人呢,就是很容易忘掉以前的教訓的了。第一個告訴我不能這麼幹的人其實是小學三年級的

Vczh Library++ 3.0之可配置語法分析器(FpMacro及程式碼)

    上一篇文章基本上把分析的過程都講完了,於是這次就把FpMacro作為一個Demo拿了出來。不第一次就發的原因主要是那個時候FpMacro剛剛寫完,當然寫完就要用的,於是後來就在Vczh Library++ 3.0的庫裡面大量使用了FpMacro作為程式碼生成的一個工具,用來代替一部分的巨集

Vczh Library++3.0之可配置語法分析器(分析Demo:函式式巨集)

    上一篇文章提到了我開發了可配置語法分析器之後做了一個FpMacro用來生成C++有規律的程式碼。這一篇文章就從FpMacro入手,分析可配置語法分析器所需要具備的功能。首先讓我們來了解一下什麼是FpMacro。    FpMacro主要用來產生用C++巨集很難容易產生的程式碼(譬如BOOS