编译原理课设-SLR语法分析

9次阅读

共计 4912 个字符,预计需要花费 13 分钟才能阅读完成。

语法分析

GUET 编译原理课设,当时找了很多资料,网上的资料乱七八糟,花了哥哥我好久时间。
致谢:代码的算法有参考书本其他博主的,表示感谢,同时也更正他们的了一些微小错误和不合理地方。
这里,我用书本的例子数据作为测试。

西北工业大学出版社《编译原理》蒋立源 第 3 版
第 157 页


代码中的约定:

  • 用 0 表示空
  • 用 102 表示移进 s2
  • 用 53 表示规约 r3
#include <iostream>

#include<stdio.h>

#include<stdlib.h>


using namespace std;

// 0 为空白
//102 表示 S2
//51 表示 r1
int actionTable[12][6] = {
    102,0,0,0,0,0,
    0,0,0,0,0,-1,
    0,104,0,0,0,0,
    0,0,105,0,0,0,
    0,0,53,0,0,0,
    0,107,0,108,0,0,
    0,0,0,0,109,0,
    0,0,52,0,0,0,
    0,0,110,0,55,0,
    0,0,0,0,0,51,
    0,0,0,108,0,0,
    0,0,0,0,54,0
};

int gotoTable[12][3] = {
    1,0,0,0,0,0,
    0,3,0,0,0,0,
    0,0,0,0,0,6,
    0,0,0,0,0,0,
    0,0,0,0,0,0,
    0,0,11,0,0,0
};

// 语法表,存储读取的文法
char Grammar[20][10] = {'\0'};

char vtArray[10], vnArray[10];

//action 表横坐标数组:用于定位,查表
char actionAxis[6] = {'b', 'd', 't', 's', 'e', '#'};

//goto 表横坐标数组:用于定位,查表
char gotoAxis[3] = {'B', 'D', 'S'};

// 非终结符数量,终结符数量,状态数量
int vnNumber, vtNumber, stateNumber = 12;
int LR[10];
int grammarNum;
typedef struct {
    char * base;
    char * top;
}
SymbolStack;

typedef struct {
    int * base;
    int * top;
}
StateStack;

StateStack state;
SymbolStack symbol;


// 扫描文法文件,得到文法
// 左部符号存储在第一列,即 Grammar[i][0]
int scanGrammar() {FILE * fp = fopen("slr.txt", "r");
    FILE * tp;
    char ch, nextCh;
    int i = 0, j = 0, k, count;
    while (!feof(fp)) {fscanf(fp, "%c", &ch);
        // 文件结束标志
        if (ch == '?') {Grammar[i][j] = '\0';
            break;
        }
        if (ch == '\n') {Grammar[i][j] = '\0';
            // 转移到下一行第一列
            i++;
            j = 0;
            continue;
        }
        if (ch == '-') {
            tp = fp;
            fscanf(tp, "%c", &nextCh);
            if (nextCh == '>') {
                fp = tp;
                continue;
            }
        }
        if (ch == '|') {Grammar[i + 1][0] = Grammar[i][0];
            Grammar[i][j] = '\0';
            i++;
            j = 1;
            continue;
        }
        Grammar[i][j] = ch;
        if (ch >= 'A' && ch <= 'Z') {
            count = 0;
            while (vnArray[count] != ch && vnArray[count] != '\0') {count++;}
            if (vnArray[count] == '\0') {
                vnNumber = count + 1;
                // 拓广文法的开始符 W
                if (ch == 'W') {
                    j++;
                    continue;
                }
                vnArray[count] = ch;
                vnNumber = count + 1;
            }
        }
        else {
            count = 0;
            while (vtArray[count] != ch && vtArray[count] != '\0') {count++;}
            if (vtArray[count] == '\0') {vtArray[count] = ch;
                vtNumber = count + 1;
            }
        }
        j++;
    }
    cout << "输入的文法:" << endl;

    for (k = 0; k <= i; k++) {
        j = 0;
        while (Grammar[k][j] != '\0') {if (j == 1) {printf("->");
            }
            printf("%c", Grammar[k][j]);
            j++;
        }
        cout << endl;
    }
    count = 0;
    cout << endl << "vn:" << endl;
    while (vtArray[count] != '\0') {printf("%3c", vtArray[count]);
        count++;
    }
    vtArray[count] = '#';
    vtNumber = count + 1;
    printf("%3c", vtArray[count]);
    cout << endl << "vn:" << endl;
    count = 0;
    while (vnArray[count] != '\0') {printf("%3c", vnArray[count]);
        count++;
    }
    cout << endl;
    fclose(fp);
    grammarNum = i + 1;
    return i;
}

// 计算 LR(0)项目长度,决定了:规约时符号栈和状态栈的出栈次数
int getLRLength() {
    int i, j;
    for (i = 0; i < grammarNum; i++) {
        j = 1;
        while (Grammar[i][j] != '\0') {j++;}
        // 产生式 i 的长度为 j
        LR[i] = j;
    }
    return 0;
}


// 创建栈
void createStack() {state.base = (int *)malloc(100 * sizeof(int));
    if (!state.base)
        exit(1);
    state.top = state.base;
    *state.top = 0;
    symbol.base = (char *)malloc(100 * sizeof(char));
    if (!symbol.base)
        exit(1);
    symbol.top = symbol.base;
    *symbol.top = '#';
}

// 查 Action 表
int getActionValue(int stateTop, char ch) {
    int i, j;
    // 查找

    // 更改 i 为 stateTop
    /*for (i = 0; i < stateNumber; i++) {if (stateTop == i) {break;}
    }*/
    // 查找横坐标数组 actionAxis,定位
    for (j = 0; j < vtNumber; j++) {if (ch == actionAxis[j])
            break;
    }
    return actionTable[stateTop][j];
}


// 查 Goto 表
int getGotoValue(int stateTop, char inputChar) {
    int i, j;
    for (j = 0; j < vnNumber; j++) {if (inputChar == gotoAxis[j])
            break;
    }
    if (gotoTable[stateTop][j] == 0) {//cout << "Error" << endl;}
    return gotoTable[stateTop][j];
}

// 输出信息
int printInfo(int count, int i, char chars[], int actionValue) {
    int * p = state.base, stateNum;
    int j, jj;
    char * q = symbol.base, symbolNum;
    printf("%d\t", count);
    while (p != state.top + 1) {
        stateNum = *p;
        printf("%d", stateNum);
        p++;
    }
    printf("\t");
    while (q != symbol.top + 1) {
        symbolNum = *q;
        printf("%c", symbolNum);
        q++;
    }
    printf("\t");
    j = i;
    jj = 0;
    while (jj < j) {printf(" ");
        jj++;
    }
    while (chars[j] != '\0') {printf("%c", chars[j]);
        j++;
    }

    if (actionValue > 100) {cout << "\t\ts" << actionValue - 100 << "\t" << actionValue - 100 << endl;}
    // 如果是规约,把预留下一状态给规约程序输出,在此不清除下一状态为多少
    else if (actionValue > 50) {cout << "\t\tr" << actionValue - 50 << "\t";}
    else if (actionValue == -1) {cout << "\t\tacc" << "\n\n 可以识别的输入串 \n" << endl;}
    else {return 0;}
    return 1;
}

// 规约 -- 根据编号为 i 的产生式进行规约
// 规约的结果是一个非终结符号,即 Grammar[i][0]
int redution(int i) {
    int * p, stateNum, gotoValue, LRLength;
    LRLength = LR[i] - 1;
    while (LRLength != 0) {
        state.top--;
        symbol.top--;
        LRLength--;
    }
    int temp = *state.top;
    state.top++;
    *state.top = getGotoValue(temp, Grammar[i][0]);
    symbol.top++;
    *symbol.top = Grammar[i][0];

    stateNum = *state.top;
    if (*state.top == 0) {return *state.top;}
    return *state.top;
}


// 扫描输入字符串
int scanChars() {char chars[20] = {'b', 'd', 't', 's',  'e','#'};
    int i = 0, stepCount = 1;
    int actionValue, nextActionValue;
    int stateTop, gotoValue;
    //scanf("%s", &chars);
    cout << "步骤 \t 状态 \t 栈中 \t 余留符号    分析动作 下一状态" << endl;
    while (chars[i] != '\0') {
        stateTop = *state.top;

        // 向前查看一个符号,查 action 表
        actionValue = getActionValue(stateTop, chars[i]);
        // 如果是移进,就可以输出下一状态
        // 如果是规约,则等到规约完毕再输出下一状态,因为现在不可知
        printInfo(stepCount, i, chars, actionValue);

        // 数组(表格)的值
        if (actionValue == 0) {
            cout <<endl<< "不合法的字符串!" << endl;
            break;
        }

        //acc 接受
        if (actionValue == -1) {
            stepCount++;
            return 1;
        }

        //s 移进
        if (actionValue >= 100) {
            actionValue = actionValue - 100;
            state.top++;
            *state.top = actionValue;
            symbol.top++;
            *symbol.top = chars[i];
            i++;
            stepCount++;
        }
        //r 规约
        if (actionValue >= 50 && actionValue < 100) {
            actionValue = actionValue - 50;
            gotoValue = redution(actionValue);
            // 规约完毕后,输出下一状态
            cout << gotoValue << endl;
            stepCount++;
        }
    }
    return 0;
}

int main() {scanGrammar();
    getLRLength();
    createStack();
    scanChars();
    system("pause");
    return 0;
}

文法 slr.txt
问号结尾

W->B
B->bDtSe
D->Dtd
D->d
S->stS
S->s?

正文完
 0