LL(1)語法分析


  • 根據某一文法編制調試 LL ( 1 )分析程序,以便對任意輸入的符號串進行分析。
  • 構造預測分析表,並利用分析表和一個棧來實現對上述程序設計語言的分析程序。
  • 分析法的功能是利用LL(1)控制程序根據顯示棧頂內容、向前看符號以及LL(1)分析表,對輸入符號串自上而下的分析過程。

設計思想

(1)定義部分:定義常量、變量、數據結構。

(2)初始化:設立LL(1)分析表、初始化變量空間(包括堆棧、結構體、數組、臨時變量等);

(3)控制部分:從鍵盤輸入一個表達式符號串;

(4)利用LL(1)分析算法進行表達式處理:根據LL(1)分析表對表達式符號串進行堆棧(或其他)操作,輸出分析結果,如果遇到錯誤則顯示錯誤信息。

流程圖

源程序

#include<iostream>

#include<string>

#include<map>

#include<vector>

#include<stack>

#include<set>

#include<cstring>

using namespace std;

map<char, int>getnum;

char text[100]; //獲得對應字符

vector<string>proce;

int table[100][100]; //預測分析表

int num = 0; int numvt = 0; //numvt是終結符集合,0是'#',numvt表空字

string first[100];

string follow[200];

void readin()

{

    memset(table, -1, sizeof(table));

    getnum['#'] = 0;

    text[0] = '#';

    cout << "請輸入所有的終結符:" << endl;

    char x;

    do

    {

        cin >> x;

        getnum[x] = ++num;

        text[num] = x;

    } while (cin.peek() != '\n');

    numvt = ++num;

    getnum['@'] = numvt; //kong zi

    text[num] = ('@');

    cout << "請輸入所有非終結符:" << endl;

    do

    {

        cin >> x;

        getnum[x] = ++num;

        text[num] = x;

    } while (cin.peek() != '\n');

    cout << "輸入產生式集合(空字用'@'表示),以'end'結束:" << endl;

    string pro;

    while (cin >> pro&&pro != "end")

    {

        string ss;

        ss += pro[0];

        for (int i = 3; i<pro.size(); i++)

        {

            if (pro[i] == '|')

            {

                proce.push_back(ss);

                ss.clear(); ss += pro[0];

            }

            else

            {

                ss += pro[i];

            }

        }

        proce.push_back(ss);

    }

}

void jiaoji(string &a, string b) //a=a or b 取a,b交集賦值給a

{

    set<char>se;

    for (int i = 0; i<a.size(); i++)

        se.insert(a[i]);

    for (int i = 0; i<b.size(); i++)

        se.insert(b[i]);

    string ans;

    set<char>::iterator it;

    for (it = se.begin(); it != se.end(); it++)

        ans += *it;

    a = ans;

}

string get_f(int vn, int & has_0) //dfs:vn能推出的不含空字的vt集合,並且判斷vn能否推出空字

{

    if (vn == numvt)has_0 = 1;

    if (vn<numvt)return first[vn];

    string ans;

    for (int i = 0; i<proce.size(); i++)

    {

        if (getnum[proce[i][0]] == vn)

            ans += get_f(getnum[proce[i][1]], has_0);

    }

    return ans;

}

void getfirst()

{

    for (int i = 1; i <= numvt; i++) //終結符,first集是其本身。

    {

        first[i] += ('0' + i);

    }

    for (int j = 0; j<proce.size(); j++) //掃描所有產生式

    {

        int k = 0; int has_0 = 0; //k掃瞄該產生式

        do{

            has_0 = 0;

            k++;

            if (k == proce[j].size()) //推到最后一個了,則附加空字

            {

                first[getnum[proce[j][0]]] += ('0' + numvt);

                break;

            } //合並之

            jiaoji(first[getnum[proce[j][0]]], get_f(getnum[proce[j][k]], has_0));

        } while (has_0); //到無法推出空字為止

    }

}

void print_first()

{

    cout << "first集:" << endl;

    for (int i = 1; i <= num; i++)

    {

        cout << "first [" << text[i] << "]: ";

        for (int j = 0; j<first[i].size(); j++)

            cout << text[first[i][j] - '0'] << " ";

        cout << endl;

    }

    cout << endl;

}

void getfollow()

{

    jiaoji(follow[getnum[proce[0][0]]], "0"); //先添加'#';

    for (int j = 0; j<proce.size(); j++) //掃所有產生式

    {

        for (int jj = 1; jj<proce[j].size(); jj++) //每個非終結符的follow集

        {

            if (getnum[proce[j][jj]] <= numvt)continue; //vt無follow集

            int k = jj; int has_0;

            do

            {

                has_0 = 0;

                k++;

                if (k == proce[j].size()) //都能推出空字,follow集=產生式左邊的vn,

                {

                    jiaoji(follow[getnum[proce[j][jj]]], follow[getnum[proce[j][0]]]);

                    break;

                }

                jiaoji(follow[getnum[proce[j][jj]]], get_f(getnum[proce[j][k]], has_0));

            } while (has_0);

        }

    }

}

void gettable() //得預測分析表

{

    for (int i = 0; i<proce.size(); i++) //掃所有產生式

    {

        if (proce[i][1] == '@') //直接推出空字的,特判下(follow集=產生式左邊的vn中元素填)

        {

            string flw = follow[getnum[proce[i][0]]];

            for (int k = 0; k<flw.size(); k++)

            {

                table[getnum[proce[i][0]]][flw[k] - '0'] = i;

            }

        }

        string temps = first[getnum[proce[i][1]]];

        for (int j = 0; j<temps.size(); j++) //考察first集

        {

            if (temps[j] != ('0' + numvt))

            {

                table[getnum[proce[i][0]]][temps[j] - '0'] = i;

            }

            else //有空字的,考察follw集

            {

                string flw = follow[getnum[proce[i][1]]];

                for (int k = 0; k<flw.size(); k++)

                {

                    table[getnum[proce[i][0]]][flw[k] - '0'] = i;

                }

            }

        }

    }

}

string get_proce(int i) //由對應下標獲得對應產生式。

{

    if (i<0)return " "; //無該產生式

    string ans;

    ans += proce[i][0];

    ans += "->";

    //ans+=(proce[i][0]+"->"); 注意這樣不行!思之即可。

    for (int j = 1; j<proce[i].size(); j++)

        ans += proce[i][j];

    return ans;

}

void print_table()

{

    cout << "預測分析表:" << endl;

    for (int i = 0; i<numvt; i++)

        cout << '\t' << text[i];

    cout << endl;

    for (int i = numvt + 1; i <= num; i++)

    {

        cout << text[i];

        for (int j = 0; j<numvt; j++)

        {

            cout << '\t' << get_proce(table[i][j]);

        }

        cout << endl;

    }

    cout << endl;

}

void print_follow()

{

    cout << "follow集:" << endl;

    for (int i = numvt + 1; i <= num; i++)

    {

        cout << "follow [" << text[i] << "]: ";

        for (int j = 0; j<follow[i].size(); j++)

            cout << text[follow[i][j] - '0'] << " ";

        cout << endl;

    }

    cout << endl;

}

string word;

bool analyze() //總控,分析字word的合法性,若合法,輸出所有產生式。

{

    stack<char>sta;

    sta.push('#'); sta.push(proce[0][0]);

    int i = 0;

    while (!sta.empty())

    {

        int cur = sta.top();

        sta.pop();

        if (cur == word[i]) //是終結符,推進

        {

            i++;

        }

        else if (cur == '#') //成功,結束

        {

            return 1;

        }

        else if (table[getnum[cur]][getnum[word[i]]] != -1) //查表

        {

 

            int k = table[getnum[cur]][getnum[word[i]]];

            cout << proce[k][0] << "->";

            for (int j = 1; j<proce[k].size(); j++)

                cout << proce[k][j];

            cout << endl;

            for (int j = proce[k].size() - 1; j>0; j--) //逆序入棧

            {

                if (proce[k][j] != '@')

                    sta.push(proce[k][j]);

            }

        }

        else //失敗!

        {

            return 0;

        }

    }

    return 1;

}

int main()

{

    readin();

    getfirst();

    getfollow();

    getfollow();

    gettable();

    print_first();

    print_follow();

    print_table();

    cout << "請輸入字:" << endl;

    cin >> word;

    if (analyze())

        cout << "succeed!該字有效,所用產生式如上。" << endl;

    else cout << "error!" << endl;

    return 0;

}

 

結果


免責聲明!

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



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