兩週自制腳本語言-第5天 設計語法分析器

第5天 設計語法分析器

5.1 Stone語言的語法

代碼清單 5.1 Stone 語言的語法定義

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
    program        : [ statement ] (";" | EOF)

5.2 使用解析器和組合子

Parser庫: 一種解析器組合子類型的庫 工做是將BNF寫成的語法規則改寫成Java語言程序 在書中第十七章有詳細解說html

代碼清單 5.2 Stone 語言的語法分析器BasicParser.java

//代碼清單5.2 由代碼清單5.1中列出的Stone語言語法轉換而成的語法分析程序。

/*
  A basic Parser for Stone grammatical analysis
 */
package stone;

import stone.Parser.Operators;
import stone.ast.*;

import java.util.HashSet;

import static stone.Parser.rule;

public class BasicParser {
    HashSet<String> reserved = new HashSet<String>();
    Operators operators = new Operators();
    Parser expr0 = rule();
    Parser primary = rule(PrimaryExpr.class)
        .or(rule().sep("(").ast(expr0).sep(")"),
            rule().number(NumberLiteral.class),
            rule().identifier(Name.class, reserved),
            rule().string(StringLiteral.class));
    Parser factor = rule().or(rule(NegativeExpr.class).sep("-").ast(primary),
                              primary);                               
    Parser expr = expr0.expression(BinaryExpr.class, factor, operators);

    Parser statement0 = rule();
    Parser block = rule(BlockStmnt.class)
        .sep("{").option(statement0)
        .repeat(rule().sep(";", Token.EOL).option(statement0))
        .sep("}");
    Parser simple = rule(PrimaryExpr.class).ast(expr);
    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),
            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("+", 3, Operators.LEFT);
        operators.add("-", 3, Operators.LEFT);
        operators.add("*", 4, Operators.LEFT);
        operators.add("/", 4, Operators.LEFT);
        operators.add("%", 4, Operators.LEFT);
    }
    public ASTree parse(Lexer lexer) throws ParseException {
        return program.parse(lexer);
    }
}

Parser類與Operators類都是由庫提供的類。java

rule方法是Parser類中的一個static方法express

primary字段的定義基於非終結符primary的語法規則。factor與block同理,都是相應的Java語言形式的語法規則。編程

終結符:不能單獨出如今推導式左邊的符號,也就是說終結符不能再進行
推導。

非終結符: 不是終結符的都是非終結符。非終結符可理解爲一個可拆分元素,而終結符是不可拆分的最小元素。segmentfault

表5.1 Parser類的方法

file

語法規則的處理

paren : "(" expr ")"

轉換爲Java語言後將獲得下面的代碼編程語言

Parser paren = rule().sep("(").ast(expr).sep(")");

file

factor : "-" primary | primary

對應factor字段的定義以下ide

Parser factor = rule().or(rule().sep("-").ast(primary), primary);

file

expr : factor { OP factor }

=>學習

Parser expr = expr0.expression(BinaryExpr.class, factor, operators);

運算符表以Operators對象的形式保存,它是expression方法的第三個參數。測試

operators.add("=", 1, Operators.RIGHT);
// Operator.RIGHT 右結合
// Operator.LEFT 左結合

​ add方法的參數分別是用於表示運算符的字符串、它的優先級以及左右結合順序。用於表示優先級的數字是一個從1開始的int類型數值,該值越大,優先級越高。spa

5.3 由語法分析器生成的抽象語法樹

Parser對象的parse方法將在成功執行語法分析後以抽象語法樹的形式返回分析結果。
file
語法規則

adder: NUMBER "+" NUMBER

改寫爲Java語言

Parser adder = rule().number().token("+").number();

以token添加 + 號

Parser adder = rule(BinaryExpr.class).number(NumberLiteral.class)
.token("+")
.number(NumberLiteral.class)

使用sep向模式添加分隔符

Parser adder = rule().number().sep(「+」).number();

ast方法向模式添加非終結符。

Parser eq = rule().ast(adder).token("==").ast(adder);

file

特殊的規定:若是子節點只有一個,Parser庫將不會另外建立一個額外的節點。
file
規定不適用於rule方法的參數接收了一個類的狀況
建立以NegativeExpr對象爲根的子樹

rule(NegativeExpr.class).sep("-").ast(primary)

若是但願在rule方法接受參數時也應用這條特殊規則,須要想下面這樣做爲參數的類定義簽名方法

public static ASTree create(List<ASTree> c) {
        return c.size() == 1 ? c.get(0) : new PrimaryExpr(c);
}

將非終結符progrm的語法規則改寫成Java語言

program : [ statement ] ("," | EOF)
Parser program = rule().or(statement, rule(NullStmnt.class))
.sep(";",Token.EOF);

5.4 測試語法分析器

知識補充

什麼是DSL

簡單查詢了DSL,發現仍是挺重要的 有時間詳細學習下

Wikipedia 對於 DSL 的定義

A specialized computer language designed for a specific task.

爲了解決某一類任務而專門設計的計算機語言。

DSL 是 Domain Specific Language 的縮寫,中文翻譯爲領域特定語言(下簡稱 DSL);而與 DSL 相對的就是 GPL.

GPL 是 General Purpose Language 的簡稱,即通用編程語言,也就是咱們很是熟悉的 Objective-C、Java、Python 以及 C 語言等等。

DSL 經過在表達能力上作的妥協換取在某一領域內的高效

參考

https://www.cnblogs.com/feng9...

https://zhuanlan.zhihu.com/p/...

相關文章
相關標籤/搜索