pl/0词法分析器实验代码

在基本要求中,增加了一个学生,姓名,的基本字

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXSIZE 999
#define norw 13 //关键字个数
#define txmax 999 //名字表容量
#define al 16 //符号最大长度
#define NAME "姓名"
#define STUNUM "学号"
#define REALNAME "董楚梁"

//单词种别,nul表示不能识别
enum symbol
{
    //非法,标识符,数字
    nul, ident, number,
    //运算符
    plus, minus, times, slash, eql, neq, lss, leq, gtr, geq, becomes,
    //界符
    lparen, rparen, comma, semicolon, period,
    //基本字13 +1(自己的"姓名""学号""董楚梁")
   beginsym, endsym, ifsym, thensym, whilesym, writesym, readsym, dosym, callsym, oddsym, constsym, varsym, procsym, yessym
};

enum symbol wsym[norw+1]; //保留字对应的符号值,1自己定义基本字
enum symbol ssym[256];    //单字符的符号值

//名字表结构
struct tablestruct {
    char name[al + 1]; //符号
    symbol sym; //符号种别
}table[txmax];

char str[MAXSIZE];  //存储文件内容                         
FILE* fin;
int t = 0;    //计数,在给table赋值时使用
//保留字
char word[norw][al] = { "begin","call","const","do","end","if","odd",
                    "procedure","read","then","var","while","write" };//顺序排列,方便二分查找

bool IsChinese(char ch)
{
    if ((ch >> 8) == -1)
        return true;
    return false;
}
//bool IsChinese(char ch)
//{
//	if(ch>=0&&ch<=127)
//		return true;
//	return false;
//}



//读入并保存文件内容,保存到str[MAXSIZE]中
void read() {
    char ch;
    strcpy(str, "");
    int i = 0;
    if (!fin)
    {
        printf("打开文件失败!\n");
        exit(-1);
    }
    while ((ch = fgetc(fin)) != EOF)
    {
        if (ch != '\n' && ch != '\t')
            str[i++] = ch;
        else //换行和Tab均保存为空格
            str[i++] = ' ';
    }//读入文件中内容
    str[i] = '\0';
    //printf("%s", str);
    fclose(fin);
}

//初始化
void init() {
    read();
    //设置单字符符号
    for (int i = 0; i < 256; i++)
    {
        ssym[i] = nul;
    }
    ssym['+'] = plus;
    ssym['-'] = minus;
    ssym['*'] = times;
    ssym['/'] = slash;
    ssym['('] = lparen;
    ssym[')'] = rparen;
    ssym['='] = eql;
    ssym[','] = comma;
    ssym['.'] = period;
    ssym['#'] = neq;
    ssym[';'] = semicolon;

    //保留字对应符号
    wsym[0] = beginsym;
    wsym[1] = callsym;
    wsym[2] = constsym;
    wsym[3] = dosym;
    wsym[4] = endsym;
    wsym[5] = ifsym;
    wsym[6] = oddsym;
    wsym[7] = procsym;
    wsym[8] = readsym;
    wsym[9] = thensym;
    wsym[10] = varsym;
    wsym[11] = whilesym;
    wsym[12] = writesym;
    wsym[13] = yessym;
}

//获取符号种别,并且存储到结构体数组中
void getsym() {
    int len = strlen(str);
    //printf("符号长度%d\n", len);
    int j = 0, k=0, pos = 0;
    char s[al + 1];//临时符号
    while (pos < len && j < len)
    { 
        strcpy(s, "");//s初始化
        j = k = 0;
        //空格直接跳过
        while (str[pos] == ' ')
        {
            pos++;
        }
        //以字母开头,可能是标识符或保留字,英文或者字符
       if (!IsChinese(str[pos])&&pos<len)//英文打头
        {
            if (str[pos] >= 'a' && str[pos] <= 'z')
            {
                j = pos;
                int flag=0;
                do
                { 
                   if (flag< al)
                    {
                        s[k++] = str[j++];
                        flag++;
                    }
                   else
                   {
                       j++;
                   }
                } while ((str[j] >= 'a' && str[j] <= 'z') || (str[j] >= '0' && str[j] <= '9'));
                s[k] = '\0';
                int m = 0, n = norw - 1;
                //折半查找,看字符串是否是保留字
                do {
                    k = (m + n) / 2;
                    if (strcmp(s, word[k]) <= 0)
                    {
                        n = k - 1;
                    }
                    if (strcmp(s, word[k]) >= 0)
                    {
                        m = k + 1;
                    }
                } while (m <= n);
                strcpy(table[t].name, s);
                if (m - 1 > n) //基本字
                {
                    table[t].sym = wsym[k];
                }
                else //标识符
                {
                    table[t].sym = ident;
                }
                t++;
                pos = j;
            }
            else
            {
                if (str[pos] >= '0' && str[pos] <= '9') //数字
                {
                    j = pos;
                    table[t].sym = number;
                    while (str[j] >= '0' && str[j] <= '9')
                        s[k++] = str[j++];
                    s[k] = '\0';
                    strcpy(table[t].name, s);
                    pos = j;
                    t++;
                }
                else
                {
                    if (str[pos] == ':') {
                        if (str[pos + 1] == '=') {//:=运算符
                            table[t].sym = becomes;
                            strcpy(table[t].name, ":=");
                            pos += 2;
                        }
                        else {//非法字符,设置为nul
                            table[t].sym = nul;
                            s[0] = ':'; s[1] = '\0';
                            strcpy(table[t].name, s);
                            pos++;
                        }
                        t++;
                    }
                    else
                    {
                        if (str[pos] == '<') {
                            if (str[pos + 1] == '=') {// <=
                                table[t].sym = leq;
                                strcpy(table[t].name, "<=");
                                pos += 2;
                            }
                            else {// <
                                table[t].sym = lss;
                                strcpy(table[t].name, "<");
                                pos++;
                            }
                            t++;
                        }
                        else
                        {
                            if (str[pos] == '>') {
                                if (str[pos + 1] == '=') {// >=
                                    table[t].sym = geq;
                                    strcpy(table[t].name, ">=");
                                    pos += 2;
                                }
                                else {// >
                                    table[t].sym = gtr;
                                    strcpy(table[t].name, ">");
                                    pos++;
                                }
                                t++;
                            }
                            else
                            {//其它单个字符
                                table[t].sym = ssym[str[pos]];
                                s[0] = str[pos]; s[1] = '\0';
                                strcpy(table[t].name, s);
                                t++;
                                pos++;
                            }
                        }
                    }
                }
            }
        }
       else//中文
       {
       j = pos;
       int flag = 0;
       do
       {
           if (flag < al)
           {
               s[k++] = str[j++];
               flag++;
           }
           else
           {
               j++;
           }
       } while ((str[j] >> 8) == -1|| (str[j] >= '0' && str[j] <= '9'));
       s[k] = '\0';
       strcpy(table[t].name, s);
       int ret1 = strcmp(s, STUNUM);
       int ret2 = strcmp(s, NAME);
       int ret3 = strcmp(s, REALNAME);
	   if (!ret1 || !ret2 || !ret3)
       {
           table[t].sym = wsym[13];
       }
       t++;
       pos = j;
       }           
    }
}

//输出表内容
void print() {
    int i;
    for (i = 0; i < t; i++)
    {
        printf("%-15s ", table[i].name);
        if (table[i].sym == 0)
        {
            printf("非法");
        }
        else if (table[i].sym == 1)
        {
            printf("标识符");
        }
        else if (table[i].sym == 2)
        {
            printf("数字");
        }
        else if (table[i].sym >= 3 && table[i].sym <= 13)
        {
            printf("运算符");
        }
        else if (table[i].sym >= 14 && table[i].sym <= 18)
        {
            printf("界符");
        }
        else
        {
            printf("基本字");
        }
        printf("\n");
    }
}

int main()
{
    fin = fopen("a.txt", "r");
    init();
    getsym();
    print();
	system("pause");
    return 0;
}
const a=10;
var b,c;
procedure p;
begin
c:=b+a;
end;
begin
姓名:董楚梁1
end.
学号:202002156023

实验结果:

 

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在《算法+数据结构=程序》一书中,Niklaus Wirth 设计的 PL/0 语言编译器分成两部分,把源语言翻译成中间语言的编译器和中间语言解释器,编译器用的是递归下降的预测分析方法中间语言是一种栈机器代码,其指令集是根据 PL/0 语言的需要来设计的。编译器源码及测试程序可从。一条指令由三个域组成: (1)操作码 f:上面已经列出了所有 8 种操作码。 (2)层次差 l:这里的层次差就是 5.3.2 节介绍嵌套深度时的 n p − n a 。该域仅用于存取指令和调用指令。 (3)多用途 a:在运算指令中,a 的值用来区分不同的运算;在其他情况,a 或是一个数(lit,int),或是一个程序地址(jmp,jpc,cal),或是一个数据地址(lod,sto)。 编译器对 PL/0 源程序进行一遍扫描,并逐行输出源程序。在源程序无错的情况下,编译器每编译完一个分程序,就列出该分程序的代码,这由编译器的 listcode 过程完成。每个分程序的第一条指令是 jmp 指令,其作用是绕过该分程序声明部分产生的代码(即绕过内嵌过程的代码)。listcode 过程没有列出这条代码。 解释器是编译器中的一个过程,若源程序无错,则编译结束时调用解释过程 interpret。由于 PL/0 语言没有输出语句,解释器按执行次序,每遇到对变量赋值时就输出该值。 由于 PL/0 语言是过程嵌套语言,因此程序运行时,活动记录栈中每个活动记录需要包含控制链和访问。活动记录栈的栈顶以外的存储空间作为代码执行过程中所需要的计算栈,无需另外设立计算栈。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值