20分鍾快速編寫簡易計算器


一、從Gitee上下載編譯器框架的可執行包並解壓,可以得到一個jar文件,我們不執行jar文件,而是作為一個模塊導入。

(https://gitee.com/llyronx/LYRON/attach_files/329927/download 或者 https://github.com/LLyronx/LYRON/releases/download/0.5/LYRON-0.5.zip)。

二、使用Intellij IDEA新建一個Java工程,然后將lib和jar包移動到工程文件夾下。

三、在Project Structure中設置Dependencies,添加加入的jar文件。

四、新建一個XML文件,寫下計算器的基本文法:

<?xml version="1.0" encoding="UTF-8" ?>

<pldl>
    <cfgproductions>
        <item>
            <production> Program -> E </production>
        </item>
        <item>
            <production> E -> E + T</production>
        </item>
        <item>
            <production> E -> E - T</production>
        </item>
        <item>
            <production> E -> T </production>
        </item>
        <item>
            <production> T -> T * F</production>
        </item>
        <item>
            <production> T -> T / F</production>
        </item>
        <item>
            <production> T -> F </production>
        </item>
        <item>
            <production> F -> num</production>
        </item>
        <item>
            <production> F -> ( E )</production>
        </item>
    </cfgproductions>

    <terminators>
        <item>
            <name>num</name>
            <regex>[1-9][0-9]*|0</regex>
        </item>
    </terminators>

    <comments></comments>
</pldl>

五、完善<movements>:在每個文法產生式增加簡單的屬性傳遞動作,其中加減乘除產生式的屬性傳遞動作都相同:

<?xml version="1.0" encoding="UTF-8" ?>

<pldl>
    <cfgproductions>
        <item>
            <production> Program -> E </production>
            <movements>
                <item>go($1)</item>
            </movements>
        </item>
        <item>
            <production> E -> E + T</production>
            <movements>
                <item>go($1)</item>
                <item>go($3)</item>
                <item>$$(val) = newTemp(var)</item>
            </movements>
        </item>
        <item>
            <production> E -> E - T</production>
            <movements>
                <item>go($1)</item>
                <item>go($3)</item>
                <item>$$(val) = newTemp(var)</item>
            </movements>
        </item>
        <item>
            <production> E -> T </production>
            <movements>
                <item>go($1)</item>
                <item>$$(val) = $1(val)</item>
            </movements>
        </item>
        <item>
            <production> T -> T * F</production>
            <movements>
                <item>go($1)</item>
                <item>go($3)</item>
                <item>$$(val) = newTemp(var)</item>
            </movements>
        </item>
        <item>
            <production> T -> T / F</production>
            <movements>
                <item>go($1)</item>
                <item>go($3)</item>
                <item>$$(val) = newTemp(var)</item>
            </movements>
        </item>
        <item>
            <production>T -> F </production>
            <movements>
                <item>go($1)</item>
                <item>$$(val) = $1(val)</item>
            </movements>
        </item>
        <item>
            <production> F -> num</production>
            <movements>
                <item>$$(val) = $1(val)</item>
            </movements>
        </item>
        <item>
            <production> F -> ( E )</production>
            <movements>
                <item>go($2)</item>
                <item>$$(val) = $2(val)</item>
            </movements>
        </item>
    </cfgproductions>

    <terminators>
        <item>
            <name>num</name>
            <regex>[1-9][0-9]*|0</regex>
        </item>
    </terminators>

    <comments></comments>
</pldl> 

六、完善生成四元式的語法動作,只需要在加減乘除產生式和Program產生式中加入<after-generations>即可,其中Program添加的語句用於結束:

<?xml version="1.0" encoding="UTF-8" ?>

<pldl>
    <cfgproductions>
        <item>
            <production> Program -> E </production>
            <movements>
                <item>go($1)</item>
            </movements>
            <after-generations>
                <item>gen(end, _, _, $1(val))</item>
            </after-generations>
        </item>
        <item>
            <production> E -> E + T</production>
            <movements>
                <item>go($1)</item>
                <item>go($3)</item>
                <item>$$(val) = newTemp(var)</item>
            </movements>
            <after-generations>
                <item>gen(add, $1(val), $3(val), $$(val))</item>
            </after-generations>
        </item>
        <item>
            <production> E -> E - T</production>
            <movements>
                <item>go($1)</item>
                <item>go($3)</item>
                <item>$$(val) = newTemp(var)</item>
            </movements>
            <after-generations>
                <item>gen(sub, $1(val), $3(val), $$(val))</item>
            </after-generations>
        </item>
        <item>
            <production> E -> T </production>
            <movements>
                <item>go($1)</item>
                <item>$$(val) = $1(val)</item>
            </movements>
        </item>
        <item>
            <production> T -> T * F</production>
            <movements>
                <item>go($1)</item>
                <item>go($3)</item>
                <item>$$(val) = newTemp(var)</item>
            </movements>
            <after-generations>
                <item>gen(multi, $1(val), $3(val), $$(val))</item>
            </after-generations>
        </item>
        <item>
            <production> T -> T / F</production>
            <movements>
                <item>go($1)</item>
                <item>go($3)</item>
                <item>$$(val) = newTemp(var)</item>
            </movements>
            <after-generations>
                <item>gen(div, $1(val), $3(val), $$(val))</item>
            </after-generations>
        </item>
        <item>
            <production>T -> F </production>
            <movements>
                <item>go($1)</item>
                <item>$$(val) = $1(val)</item>
            </movements>
        </item>
        <item>
            <production> F -> num</production>
            <movements>
                <item>$$(val) = $1(val)</item>
            </movements>
        </item>
        <item>
            <production> F -> ( E )</production>
            <movements>
                <item>go($2)</item>
                <item>$$(val) = $2(val)</item>
            </movements>
        </item>
    </cfgproductions>

    <terminators>
        <item>
            <name>num</name>
            <regex>[1-9][0-9]*|0</regex>
        </item>
    </terminators>

    <comments></comments>
</pldl>

七、編寫測試代碼進行測試,注意ConsoleApplication中LLBegin用於初始化XML文件,LLParse用於解析代碼文件(在這里則是四則運算式),LLEnd用於輸出四元式。

public static void main(String[] args) throws Exception { FileInputStream grammarInput = new FileInputStream(new File("Calculator.xml")); FileOutputStream fourTupleOutput = new FileOutputStream(new File("fourTuple.txt")); StringBufferInputStream codeInput = new StringBufferInputStream("1+2*3"); ConsoleApplication consoleApplication = new ConsoleApplication(); consoleApplication.LLBegin(grammarInput); consoleApplication.LLParse(codeInput); consoleApplication.LLEnd(fourTupleOutput); }

下面是輸出結果:

 

八、最后編寫代碼解析輸出四元式即可,只需要一個簡單的符號表(臨時變量和數值的映射):

private static int getVar(HashMap<String, Integer> symbols, String s){ return Character.isDigit(s.charAt(0)) ? Integer.valueOf(s) : symbols.get(s); } private static void putVar(HashMap<String, Integer> symbols, String s, Integer i){ symbols.put(s, i); } public static int getResult(InputStream stream){ Scanner scanner = new Scanner(stream); HashMap<String, Integer> symbols = new HashMap<>(); String last = null; while (scanner.hasNext()){ String lineIn = scanner.nextLine(); String []fourStrs = lineIn.split(","); int first, second; switch (fourStrs[0]){ case "add": first = getVar(symbols, fourStrs[1]);second = getVar(symbols, fourStrs[2]); putVar(symbols, fourStrs[3], first + second); break; case "sub": first = getVar(symbols, fourStrs[1]);second = getVar(symbols, fourStrs[2]); putVar(symbols, fourStrs[3], first - second); break; case "multi": first = getVar(symbols, fourStrs[1]);second = getVar(symbols, fourStrs[2]); putVar(symbols, fourStrs[3], first * second); break; case "div": first = getVar(symbols, fourStrs[1]);second = getVar(symbols, fourStrs[2]); putVar(symbols, fourStrs[3], first / second); break; case "end": return getVar(symbols, fourStrs[3]); } } return 0; }

在main中調用,這里我們給用戶兩種調用方式,即帶參數和不帶參數的調用:  

public static void main(String[] args) throws Exception {
        ByteArrayOutputStream tempOutputStream = new ByteArrayOutputStream(1024);
        PrintStream stdout = System.out;

        System.setOut(new PrintStream(tempOutputStream));
        FileInputStream grammarInput = new FileInputStream(new File("Calculator.xml"));
        ByteArrayOutputStream fourTupleOutput = new ByteArrayOutputStream();
        ConsoleApplication consoleApplication = new ConsoleApplication();
        consoleApplication.LLBegin(grammarInput);
        System.setOut(stdout);

        if (args.length == 0){
            System.out.println("輸入一個四則運算式,輸出結果。輸入q退出程序。");
            Scanner sc = new Scanner(System.in);
            while (true) {
                try {
                    String lineInput = sc.nextLine();
                    if (lineInput.length() > 0 && (lineInput.charAt(0) == 'q' || lineInput.charAt(0) == 'Q')){
                        System.out.println("感謝使用");
                        break;
                    }
                    tempOutputStream.reset();
                    fourTupleOutput.reset();
                    System.setOut(new PrintStream(tempOutputStream));
                    consoleApplication.LLParse(new StringBufferInputStream(lineInput));
                    consoleApplication.LLEnd(fourTupleOutput);
                    System.setOut(stdout);
                    StringBufferInputStream fourTupleInput = new StringBufferInputStream(fourTupleOutput.toString());
                    System.out.println(getResult(fourTupleInput));
                }
                catch (Exception e){
                    System.setOut(stdout);
                    System.err.println("語法錯誤");
                }
            }
        }
        else if (args.length == 1){
            try {
                tempOutputStream.reset();
                fourTupleOutput.reset();
                System.setOut(new PrintStream(tempOutputStream));
                consoleApplication.LLParse(new StringBufferInputStream(args[0]));
                consoleApplication.LLEnd(fourTupleOutput);
                System.setOut(stdout);
                StringBufferInputStream fourTupleInput = new StringBufferInputStream(fourTupleOutput.toString());
                System.out.println(getResult(fourTupleInput));
            }
            catch (Exception e){
                System.err.println("語法錯誤");
            }
        }
        else {
            System.err.println("參數不正確");
        }
    }

將代碼打包成最終的jar文件:參考教程https://blog.csdn.net/kenkao/article/details/81537131

參考如下的Project Structure:

 

運行結果:

 

 附xml文件代碼:

<?xml version="1.0" encoding="UTF-8" ?>

<pldl>
    <cfgproductions>
        <item>
            <production> Program -> E </production>
            <movements>
                <item>go($1)</item>
            </movements>
            <after-generations>
                <item>gen(end, _, _, $1(val))</item>
            </after-generations>
        </item>
        <item>
            <production> E -> E + T</production>
            <movements>
                <item>go($1)</item>
                <item>go($3)</item>
                <item>$$(val) = newTemp(var)</item>
            </movements>
            <after-generations>
                <item>gen(add, $1(val), $3(val), $$(val))</item>
            </after-generations>
        </item>
        <item>
            <production> E -> E - T</production>
            <movements>
                <item>go($1)</item>
                <item>go($3)</item>
                <item>$$(val) = newTemp(var)</item>
            </movements>
            <after-generations>
                <item>gen(sub, $1(val), $3(val), $$(val))</item>
            </after-generations>
        </item>
        <item>
            <production> E -> T </production>
            <movements>
                <item>go($1)</item>
                <item>$$(val) = $1(val)</item>
            </movements>
        </item>
        <item>
            <production> T -> T * F</production>
            <movements>
                <item>go($1)</item>
                <item>go($3)</item>
                <item>$$(val) = newTemp(var)</item>
            </movements>
            <after-generations>
                <item>gen(multi, $1(val), $3(val), $$(val))</item>
            </after-generations>
        </item>
        <item>
            <production> T -> T / F</production>
            <movements>
                <item>go($1)</item>
                <item>go($3)</item>
                <item>$$(val) = newTemp(var)</item>
            </movements>
            <after-generations>
                <item>gen(div, $1(val), $3(val), $$(val))</item>
            </after-generations>
        </item>
        <item>
            <production>T -> F </production>
            <movements>
                <item>go($1)</item>
                <item>$$(val) = $1(val)</item>
            </movements>
        </item>
        <item>
            <production> F -> num</production>
            <movements>
                <item>$$(val) = $1(val)</item>
            </movements>
        </item>
        <item>
            <production> F -> ( E )</production>
            <movements>
                <item>go($2)</item>
                <item>$$(val) = $2(val)</item>
            </movements>
        </item>
    </cfgproductions>

    <terminators>
        <item>
            <name>num</name>
            <regex>[1-9][0-9]*|0</regex>
        </item>
    </terminators>

    <comments></comments>
</pldl>

Java代碼: 

import app.ConsoleApplication;
import java.io.*;
import java.util.HashMap;
import java.util.Scanner;

public class Calculator {

    private static int getVar(HashMap<String, Integer> symbols, String s){
        return Character.isDigit(s.charAt(0)) ? Integer.valueOf(s) : symbols.get(s);
    }
    private static void putVar(HashMap<String, Integer> symbols, String s, Integer i){
        symbols.put(s, i);
    }
    public static int getResult(InputStream stream){
        Scanner scanner = new Scanner(stream);
        HashMap<String, Integer> symbols = new HashMap<>();
        String last = null;
        while (scanner.hasNext()){
            String lineIn = scanner.nextLine();
            String []fourStrs = lineIn.split(",");
            int first, second;
            switch (fourStrs[0]){
                case "add":
                    first = getVar(symbols, fourStrs[1]);second = getVar(symbols, fourStrs[2]); putVar(symbols, fourStrs[3], first + second); break;
                case "sub":
                    first = getVar(symbols, fourStrs[1]);second = getVar(symbols, fourStrs[2]); putVar(symbols, fourStrs[3], first - second); break;
                case "multi":
                    first = getVar(symbols, fourStrs[1]);second = getVar(symbols, fourStrs[2]); putVar(symbols, fourStrs[3], first * second); break;
                case "div":
                    first = getVar(symbols, fourStrs[1]);second = getVar(symbols, fourStrs[2]); putVar(symbols, fourStrs[3], first / second); break;
                case "end":
                    return getVar(symbols, fourStrs[3]);
            }
        }
        return 0;
    }

    public static void main(String[] args) throws Exception {
        ByteArrayOutputStream tempOutputStream = new ByteArrayOutputStream(1024);
        PrintStream stdout = System.out;

        System.setOut(new PrintStream(tempOutputStream));
        FileInputStream grammarInput = new FileInputStream(new File("Calculator.xml"));
        ByteArrayOutputStream fourTupleOutput = new ByteArrayOutputStream();
        ConsoleApplication consoleApplication = new ConsoleApplication();
        consoleApplication.LLBegin(grammarInput);
        System.setOut(stdout);

        if (args.length == 0){
            System.out.println("輸入一個四則運算式,輸出結果。輸入q退出程序。");
            Scanner sc = new Scanner(System.in);
            while (true) {
                try {
                    String lineInput = sc.nextLine();
                    if (lineInput.length() > 0 && (lineInput.charAt(0) == 'q' || lineInput.charAt(0) == 'Q')){
                        System.out.println("感謝使用");
                        break;
                    }
                    tempOutputStream.reset();
                    fourTupleOutput.reset();
                    System.setOut(new PrintStream(tempOutputStream));
                    consoleApplication.LLParse(new StringBufferInputStream(lineInput));
                    consoleApplication.LLEnd(fourTupleOutput);
                    System.setOut(stdout);
                    StringBufferInputStream fourTupleInput = new StringBufferInputStream(fourTupleOutput.toString());
                    System.out.println(getResult(fourTupleInput));
                }
                catch (Exception e){
                    System.setOut(stdout);
                    System.err.println("語法錯誤");
                }
            }
        }
        else if (args.length == 1){
            try {
                tempOutputStream.reset();
                fourTupleOutput.reset();
                System.setOut(new PrintStream(tempOutputStream));
                consoleApplication.LLParse(new StringBufferInputStream(args[0]));
                consoleApplication.LLEnd(fourTupleOutput);
                System.setOut(stdout);
                StringBufferInputStream fourTupleInput = new StringBufferInputStream(fourTupleOutput.toString());
                System.out.println(getResult(fourTupleInput));
            }
            catch (Exception e){
                System.err.println("語法錯誤");
            }
        }
        else {
            System.err.println("參數不正確");
        }
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM