1. 程式人生 > >編譯原理實驗(二)之語法分析

編譯原理實驗(二)之語法分析

採用實驗1的簡單語言,設計並實現含多條簡單賦值語句的語法分析程式,要求採用算符優先的分析演算法。   

注意與實驗1、2的銜接。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SyntaxAnalysis {
    struct Error {
        Word word;
        string text;
    }
    class SyntaxAnalysis {
        WordPicker wordPicker = new WordPicker("text.txt");
        List<Word> words = new List<Word>();
        int index = -1;
        List<Error> errors = new List<Error>();

        static void Main(string[] args) {
            SyntaxAnalysis syntax = new SyntaxAnalysis();
            syntax.grammerParser();
            Console.ReadKey();
        }
        /// <summary>
        /// 語法分析
        /// </summary>
        public void grammerParser() {
            do {
                functionParser();
            } while(nextWord().typeNum != WordPicker.endTypeNumber);
            if(success)
                Console.WriteLine("成功");
        }

        private void functionParser() {

            Word word = nextWord();
            //返回型別
            if(!KeyWords.isReturnType(word)) {
                addError(word, "返回值錯誤");
            }
            word = nextWord();
            //函式名
            if(!isIdentifier(word)) {
                addError(word, "函式名錯誤");
            }
            //(引數){
            word = nextWord();
            if(!isLeftBracket(word)) {
                addError(word, "(缺失");
            }
            arguments();
            word = nextWord();
            if(!isRightBracket(word)) {
                addError(word, ")缺失");
            }
            word = nextWord();
            if(word.typeNum != Symbols.left_curly_bracket.typeNum) {
                addError(word, "{缺失");
            }
            //語句串
            statementSequence();
            //}
            word = nextWord();
            if(word.typeNum != Symbols.right_curly_bracket.typeNum) {
                addError(word, "}缺失");
                retractWord();
            }

        }
        private bool isLeftBracket(Word word) {
            return word.typeNum == Symbols.left_bracket.typeNum;
        }

        private bool isRightBracket(Word word) {
            return word.typeNum == Symbols.right_bracket.typeNum;
        }

        bool success = true;
        private void addBeforeError(Word word, string v) {
            success = false;
            Console.WriteLine(word.ToPositionInfo() + "\t之前 " + v);
        }
        private void addError(Word word, string v) {
            success = false;
            Console.WriteLine(word.ToPositionInfo() + "\t" + v);
        }
        /// <summary>
        /// 引數
        /// </summary>
        private void arguments() {
            Word word = nextWord();
            if(!KeyWords.isType(word)) {
                if(isIdentifier(word))
                    addBeforeError(word, "引數型別缺失");
                else {
                    if(lastWord().typeNum == Symbols.comma.typeNum)
                        addBeforeError(word, ",多餘");
                    retractWord();
                    return;
                }
            }
            word = nextWord();
            if(!isIdentifier(word)) {
                addBeforeError(word, "引數識別符號錯誤");
                if(isRightBracket(word)) {
                    retractWord();
                    return;
                }
            }
            //逗號
            word = nextWord();
            if(word.typeNum == Symbols.comma.typeNum) {
                arguments();
            }
            else if(isRightBracket(word)) {
                retractWord();
                return;
            }

        }

        private bool isIdentifier(Word word) {
            return word.typeNum == WordPicker.identifierTypeNumber;
        }


        /// <summary>
        /// 語串
        /// </summary>
        private void statementSequence() {
            Word word = nextWord();
            while(word.typeNum != Symbols.right_curly_bracket.typeNum && word.typeNum != WordPicker.endTypeNumber) {

                if(KeyWords.isType(word)) {
                    defineStatement();
                }
                else if(isIdentifier(word)) {
                    assignStatement();
                }
                else {
                    addError(word, "多餘");
                }
                /*  else if(KeyWords.isCondition(word)) {

                   }
                   else if(KeyWords.isFORLoop(word)) {

                   }
                   else {
                      // addError(word, "多餘");
                   }*/
                word = nextWord();
            }
            retractWord();
        }
        /// <summary>
        /// 定義語句
        /// </summary>
        private void defineStatement() {
            Word word = nextWord();
            if(!isIdentifier(word)) {
                addBeforeError(word, "變數名缺失");
                retractWord();
            }
            word = nextWord();
            if(word.typeNum == Symbols.assign.typeNum) {
                expressStatement();
                word = nextWord();
            }
           
            if(word.typeNum == Symbols.comma.typeNum) {
                defineStatement();
            }
            else if(word.typeNum != Symbols.semicolon.typeNum) {
                addBeforeError(word, ";缺失");
                retractWord();
            }

        }
        /// <summary>
        /// 賦值語句
        /// </summary>
        private void assignStatement() {
            Word word = nextWord();
            if(word.typeNum != Symbols.assign.typeNum) {
                addBeforeError(word, "=缺失");
                retractWord();
            }
            expressStatement();
            word = nextWord();
            if(word.typeNum != Symbols.semicolon.typeNum) {
                    addBeforeError(word, ";缺失");
                    retractWord();
            }
           
        }
        /// <summary>
        /// 表示式
        /// </summary>
        private void expressStatement() {
           
            term();
            Word word = nextWord();
            while(word.typeNum == Symbols.add.typeNum || word.typeNum == Symbols.sub.typeNum) {
                term();
                word = nextWord();
            }         
            retractWord();

        }

        private void term() {
            factor();
            Word word = nextWord();
            while(word.typeNum == Symbols.mul.typeNum || word.typeNum == Symbols.except.typeNum || word.typeNum == Symbols.remain.typeNum) {
                factor();
                word = nextWord();
            }
            retractWord();
        }
        /// <summary>
        /// 表示式因子
        /// </summary>
        private void factor() {
            Word word = nextWord();
            if(isValue(word))
                return;
            if(word.typeNum == Symbols.left_bracket.typeNum) {
                expressStatement();
                word = nextWord();
                if(word.typeNum != Symbols.right_bracket.typeNum) {
                    addBeforeError(word, ")缺失");
                    retractWord();
                }
            }
            else {
                addBeforeError(word, "表示式錯誤");
                retractWord();
            }


        }
        /// <summary>
        /// 判斷是否是數值型別
        /// </summary>
        /// <param name="word"></param>
        /// <returns></returns>
        private bool isValue(Word word) {
            return word.typeNum == WordPicker.numberTypeNumber
                || word.typeNum == WordPicker.charTypeNumber
                || word.typeNum == WordPicker.stringTypeNumber
                || word.typeNum == WordPicker.identifierTypeNumber;
        }
        /// <summary>
        /// 讀取下一個詞
        /// </summary>
        /// <returns></returns>
        private Word nextWord() {
            index++;
            if(words.Count <= index) {
                Word w = wordPicker.Scanner();
                if(words.Count == 0 || words[words.Count - 1].typeNum != WordPicker.endTypeNumber)
                    words.Add(w);
                index = words.Count - 1;
            }
            return words[index];
        }
        /// <summary>
        /// 現在的詞
        /// </summary>
        /// <returns></returns>
        private Word nowWord() {

            if(words.Count > index && index >= 0) {
                return words[index];
            }
            return null;
        }
        /// <summary>
        /// 上一個詞
        /// </summary>
        /// <returns></returns>
        private Word lastWord() {

            if(index > 0) {

                return words[index - 1];
            }
            else {
                return null;
            }

        }
        /// <summary>
        /// 回退一個詞
        /// </summary>
        private void retractWord() {

            if(index >= 0) {
                index--;
            }

        }
    }
}

 

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace SyntaxAnalysis {
    /// <summary>
    /// 詞
    /// </summary>
    class Word {
        public int typeNum;
        public string word;
        public int col=0;
        public int row=0;
        public override string ToString() {
            return "(" + typeNum + "," + word + ")";
        }
        public string ToPositionInfo() {
            return "行:"+(row+1)+"\t列:"+col+"\t碼:"+typeNum + "\t字:" + word;
        }
    }
    

    class WordPicker {
   
        string[] input;
        //int input_index = 0;
        int row = 0;
        int col = 0;
        char character;
       
        /// <summary>
        /// 操作符表
        /// </summary>    
        string[] operatorSort = null;

        public static int identifierTypeNumber;    //變數名型別
        public static int numberTypeNumber;        //數值型別
        public static int charTypeNumber;          //字元型別
        public static int stringTypeNumber;        //字串型別
        public static int endTypeNumber = -1;      //結束符型別
        public static int errorTypeNumber = -2;    //出錯型別
        public static int noDefine = -3;           //未定義型別
        public static char nullChar = '\0';

        public WordPicker(string file) {
            input= File.ReadAllLines(file);           
            identifierTypeNumber = KeyWords.keyWordTable.Length+1;
            numberTypeNumber = KeyWords.keyWordTable.Length + 2;
            charTypeNumber = KeyWords.keyWordTable.Length + 3;
            stringTypeNumber = KeyWords.keyWordTable.Length + 4;

            operatorSort = new string[Symbols.operatorTable.Length];
            Array.Copy(Symbols.operatorTable, operatorSort, Symbols.operatorTable.Length);
            Array.Sort(operatorSort);
            Array.Reverse(operatorSort);
        }



        /// <summary>
        /// 讀詞
        /// </summary>
        /// <returns></returns>
        public Word Scanner() {
            Word myWord;          
            read();
            readValidChar();
            //識別符號
            if(char.IsLetter(character)) {
                myWord=readWord();
            }//數值
            else if(char.IsDigit(character)) {
                myWord = readDigit();
            }//字元常量
            else if(character == '\'') {
                myWord = readConstChar();
            }//字串
            else if(character == '\"') {
                myWord = readConstString();
            }/*//結束符
            else if(character == endChar) {
                myWord.word = "" + endChar;
                myWord.typeNum = endTypeNumber;
            }*///空值
            else if(character == nullChar) {
                myWord = new Word();
                myWord.row = row;
                myWord.col = col;
                myWord.word = "Ending";
                myWord.typeNum = endTypeNumber;
            }//其他字元
            else {
                myWord = readOtherChar();
            }
            return myWord;

        }
        /// <summary>
        /// 識別符號
        /// </summary>
        /// <param name="myWord"></param>
        private Word readWord() {
            Word myWord = new Word();
            myWord.row = row;
            myWord.col = col;
            while(char.IsLetter(character) || char.IsDigit(character)) {
                myWord.word += character;
                read();
            }
            retract();
            myWord.typeNum = KeyWords.getTypeNumber(myWord.word);
            return myWord;
        }
        /// <summary>
        /// 其他字元
        /// </summary>
        /// <param name="myWord"></param>
        private Word readOtherChar() {
            Word myWord = new Word();
            myWord.row = row;
            myWord.col = col;
            string s = "" + character;
            for(int i = 0; i < 2; i++) {
                read();
                if(character == nullChar) {
                    break;
                }
                s += character;
            }
            foreach(string op in operatorSort) {
                if(s.StartsWith(op)) {
                    retract(s.Length - op.Length);
                    s = op;
                    break;
                }
            }
            myWord.word = s;
            myWord.typeNum = Symbols.getTypeNumber(myWord.word);
            return myWord;
        }

        private void retract(int v) {
            if(v == 0)
                return;
            col=col-v-1;
            if(col < 0) {
                row--;
                col = input[row].Length + col;
            }
            read();
        }



        /// <summary>
        /// 識別數字常量
        /// </summary>
        /// <param name="myWord"></param>
        private Word readDigit() {
            Word myWord = new Word();
            myWord.row = row;
            myWord.col = col;
            while(char.IsDigit(character)) {
                myWord.word += character;
                read();
            }
            if(character == '.') {
                myWord.word += character;
                read();
                while(char.IsDigit(character)) {
                    myWord.word += character;
                    read();
                }
            }
            retract();
            myWord.typeNum = numberTypeNumber;
             return myWord;
        }

        /// <summary>
        /// 識別字符常量
        /// </summary>
        /// <param name="myWord"></param>
        private Word readConstChar() {
            Word myWord = new Word();
            myWord.row = row;
            myWord.col = col;
            // myWord.word = "" + character;
            read();
            //讀取直到'\''結束
            while(character != '\'') {
                myWord.word += character;
                read();
                //讀到空字元或結束字元
                if(character == nullChar /*|| character == endChar*/|| char.IsControl(character)) {
                    /* if(character == endChar) {
                         myWord.word +=endChar;
                     } */
                    myWord.typeNum = errorTypeNumber;
                    return myWord;
                }
            }
            // myWord.word += character;
            Match r = Regex.Match(myWord.word, "^(\\\\([0-7]{1,3}|x[0-9a-fA-F]+|[abfnrtv\\\\\'\"?])|[^\\\\])$");
            //轉義字元模式匹配
            if(!r.Success) {
                myWord.typeNum = errorTypeNumber;
                return myWord;
            }
            myWord.typeNum = charTypeNumber;
            return myWord;

        }
        /// <summary>
        /// 識別常量字串
        /// </summary>
        /// <param name="myWord"></param>
        private Word readConstString() {
            Word myWord = new Word();
            myWord.row = row;
            myWord.col = col;
            // myWord.word = "" + character;
            read();
            while(character != '\"') {
                myWord.word += character;
                read();
                //讀到空字元或結束字元
                if(character == nullChar || char.IsControl(character)) {
                    // myWord.word += "0";
                    myWord.typeNum = errorTypeNumber;
                    return myWord;
                }
            }
            // myWord.word += character;

            //轉義字元模式匹配
            if(!isLegalString(myWord.word)) {
                myWord.typeNum = errorTypeNumber;
                return myWord;
            }
            myWord.typeNum = stringTypeNumber;
            return myWord;
        }

        /// <summary>
        /// 合法字串書寫
        /// </summary>
        /// <param name="word"></param>
        /// <returns></returns>
        private bool isLegalString(string word) {

            int i = 0;
            while(i < word.Length) {
                if(word[i] == '\\') {
                    if(++i == word.Length)
                        return false;
                    foreach(char c in translateChar) {
                        if(c == word[i]) {
                            goto aLabel;
                        }
                    }
                    return false;
                }
            aLabel:
                i++;
            }

            return true;
        }

        const string translateChar = "abfnrtv\\\'\"?";
        const string realChar = "\a\b\f\n\r\t\v\\\'\"?";

       

        /// <summary>
        /// 轉換為真實字串
        /// </summary>
        /// <param name="word"></param>
        /// <returns></returns>
        private string toRealString(string word) {
            string res = "";
            int index;
            for(int i = 0; i < word.Length; i++) {
                if(word[i] == '\\') {
                    if(++i == word.Length)
                        throw new Exception("字串以\\結尾異常");

                    index = translateChar.IndexOf(word[i]);
                    if(index == -1)
                        throw new Exception("\\" + word[i] + "解析異常");
                    res += realChar[index];
                }
                else {
                    res += word[i];
                }
            }
            return res;
        }
        /// <summary>
        /// 讀一個字元
        /// </summary>
        void read() {
            if(input.Length <= row|| input.Length == row+1 && input[input.Length-1].Length<=col) {
                character = '\0';
            }
            else {
                if(col >= input[row].Length) {
                    col = 0;
                    row++;
                }
                character = input[row][col];
                col++;
            }
                
        }
        /// <summary>
        /// 去除無效字元
        /// </summary>
        void readValidChar() {

            while(char.IsWhiteSpace(character)) {
                if(character == '\0') {
                    return;
                }
                read();              
            }
            //判斷註釋
            if(character == '/' && input[row].Length > col) {
                ignoreNote();
            }
        }

        private void ignoreNote() {
            read();
            //註釋‘//’
            if(character == '/') {
                row++;
                col = 0;                              
                read();
                readValidChar();
            }//註釋‘/*。。。*/’
            else if(character == '*') {
               
                read();
                if(character == '\0') {
                    return;
                }
                char c;
                while(true) {
                    
                    c = character;
                    read();
                    if('*' == c && '/' == character) {
                        read();
                        readValidChar();
                        return;
                    }
                    if(character == '\0') {
                        return;
                    }                
                }
            }
            else {
                retract();
            }
        }
 
        void retract() {            
            col=col-2;
            if(col < 0) {
                row--;
                col = input[row].Length + col;
            }
            read();
        }

    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace SyntaxAnalysis {
    class KeyWords {
        /// <summary>
        /// 關鍵字表
        /// </summary>
        public static string[] keyWordTable = {
            "auto","break","case", "char","const",
            "continue","default","do","double",
            "else","enum","extern","float","for",
            "goto","if", "int","long", "register",
            "return","short","signed","sizeof","static",
            "struct","switch","typedef","union","unsigned",
            "void","volatile","while"};

        public static Word AUTO, BREAK, CASE, CHAR, CONST,
        CONTINUE, DEFAULT, DO, DOUBLE,
        ELSE, ENUM, EXTERN, FLOAT, FOR,
        GOTO, IF, INT, LONG, REGISTER,
        RETURN, SHORT, SIGNED, SIZEOF, STATIC,
        STRUCT, SWITCH, TYPEDEF, UNION, UNSIGNED,
        VOID, VOLATILE, WHILE;

        static KeyWords() {
            Type t = typeof(KeyWords);

            FieldInfo[] fields = t.GetFields();
            Word word;
            foreach(FieldInfo f in fields)
                if(f.FieldType.Equals(typeof(Word))) {
                    word = new Word();
                    word.word = f.Name.ToLower();
                    word.typeNum = getTypeNumber(word.word);
                    f.SetValue(t, word);
                }
        }
        /// <summary>
        /// 獲取關鍵字編碼
        /// </summary>
        /// <returns></returns>
        public static int getTypeNumber(string s) {
            for(int i = 0; i < keyWordTable.Length; i++) {
                if(keyWordTable[i] == s) {
                    return i+1;
                }
            }

            return WordPicker.identifierTypeNumber;
        }
        public static bool isPrefType(Word w) {
            return SIGNED.typeNum == w.typeNum
               || UNSIGNED.typeNum == w.typeNum;
        }
        public static bool isType(Word w) {
            return INT.typeNum == w.typeNum
                || CHAR.typeNum == w.typeNum
                || DOUBLE.typeNum == w.typeNum
                || FLOAT.typeNum == w.typeNum
                || SHORT.typeNum == w.typeNum;               
        }

        public static bool isReturnType(Word w) {
            return isType(w) || VOID.typeNum == w.typeNum;
        }

        internal static bool isCondition(Word word) {
            return word.typeNum == IF.typeNum;
        }

        internal static bool isFORLoop(Word word) {
            return word.typeNum == FOR.typeNum|| word.typeNum == WHILE.typeNum;
        }
        internal static bool isWhileLoop(Word word) {
            return word.typeNum == WHILE.typeNum;
        }
        internal static bool isDoLoop(Word word) {
            return  word.typeNum == DO.typeNum;
        }

        internal static bool isKeyWord(Word word) {
            return word.typeNum > 0 && word.typeNum <= keyWordTable.Length;
        }
    }
    class Symbols {
        public static string[] operatorTable = {
            "{","}","[","]","(",")","->",".",
            "++","--",
            "!","&&","||",
            "~","&","|","^",
            "+","-","*","/","%",
            "<<",">>",
            "<",">",">=","<=",
            "==","!=","?",":",",",";",
            "=","+=","-=","*=","/=","%=",
            "&=","^=","|=","<<=",">>="
        };

        public static Word left_curly_bracket, right_curly_bracket,
            left_square_bracket, right_square_bracket,
            left_bracket, right_bracket,
            arrow, point, two_add, two_sub,
            logic_not, logic_and, logic_or,
            bitwise_not, bitwise_and, bitwise_or, bitwise_xor,
            add, sub, mul, except, remain,
            left_move, right_move,
            less, greater, greater_equal, less_equal,
            equal, not_equal, question_mark, colon, comma, semicolon,
            assign, add_assign, sub_assign, mul_assign, except_assign, remain_assign,
            and_assign, xor_assign, or_assign, left_move_assign, right_move_assign;

        internal static bool isSemicolo(Word word) {
            return word .typeNum == semicolon.typeNum;
        }

        static Symbols() {
            Type t = typeof(Symbols);

            FieldInfo[] fields = t.GetFields();
            Word word;
            int index = 0;
            foreach(FieldInfo f in fields)
                if(f.FieldType.Equals(typeof(Word))) {
                    word = new Word();
                    word.word = operatorTable[index++];
                    word.typeNum = getTypeNumber(word.word);
                    f.SetValue(t, word);
                }
        }

        public static int getTypeNumber(string s) {
            int start = 100;
            for(int i = 0; i < operatorTable.Length; i++) {
                if(operatorTable[i] == s) {
                    return start + i;
                }
            }
            return WordPicker.noDefine;
        }

       
    }
}

輸入text.txt:

void main(int a,int b){	
   //int a=4-2;
   int a=a,b=a*82,c= a;
   b=12-12*x
   //long b=a-a8 b-2-2;
   //int bc=b-c*88/9;
}

輸出: