⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 合作.cpp

📁 编译原理课程设计词法分析源码及程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*
* 程序名称:编译原理之词法分析器
* 输    入:Test.c C语言源程序文件
* 输    出:Const.txt 常量表 Sign.txt 标识符表 Result.txt 二元式结果
* 编写时间:2008-6-26
* 作    者:张文明  杨倩
* 编译环境:VC6.0_CN
* 操作系统:WinXP_SP2
* 程序版本:V1.0
* 备    注:此程序采用一缓冲方式读入程序源码,首先进行预处理去掉注释和无效空格
*           然后再进行详细的词法分析,为了便于后续处理,程序设置了几个表:符号
*           表和常数表。
* 注    意:此分析器只对C语言子集进行处理
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <conio.h>
#include <stdlib.h>
#include <iostream.h>

#define KEYWORD_LEN 32        //保留字个数
#define STR_MAX_LEN 300        //标识符最大长度
#define PRO_MAX_LEN 20480    //源程序最大长度
#define STB_MAX_LEN 1000    //符号表最大容量
#define CTB_MAX_LEN 1000    //常数表最大容量

#define ERROR    0                //错误
#define ID        (KEYWORD_LEN+1)    //标识符
#define CONST    (KEYWORD_LEN+2)    //常量
#define OPERAT    (KEYWORD_LEN+3)    //运算符
#define DIVIDE    (KEYWORD_LEN+4)    //界符

int  errorLine=0;
char proBuffer[PRO_MAX_LEN] = "";    //存储程序代码的全局缓冲区
char ch;                            //读出来的当前字符
char wordget[STR_MAX_LEN];            //标识符 或 常量
int  point = 0;                        //源程序当前位置指针
char signTab[STB_MAX_LEN][STR_MAX_LEN];    //符号表
int  pointSTB = 0;                    //符号表指针
char constTab[CTB_MAX_LEN][STR_MAX_LEN];    //常量表
int  pointCTB = 0;                    //常数表指针
char kwTab[KEYWORD_LEN][60]=        //保留字表 ??字符指针数组??
       {"PROGRAM","VAR","BEGIN","DIV","END","INTEGER",
	   "AND","ARRAY","CASE","CONST","DO","DOWNTO","ELSE",
	   "FILE","FOR","FUNTION","GOTO","IF","IN","LABEL",
	   "MOD","NIL","NOT","OF","OR","PACKED","PROCEDURE"};
char errorTab[][50]={                //错误代码表
    /*0*/"未知错误",    /*1*/"非法的字符",    /*2*/"不正确的字符常量表达",
    /*3*/"不正确的字符串表达",    /*4*/"不正确的数字表达",    /*5*/"注释丢失'*/'"};

typedef struct signDuality        //二元表的定义
{
    int kind;
    int value;
}*pDualistic, Dualistic;

//函数声明
void pretreatment();    //预处理
void ProcError(int id);    //错误
bool GetChar();            //获得一个字符不包括结束标记
bool GetBC();            //获得一个非空白字符
void Concat(char *str);    //将ch连接到str后
int  Reserve(char *str);    //对str字符串查找保留字表 若是一个保留字-返回其编码 否则返回0
void Retract();            //将搜索指示器回调一个字符位置
int  InsertId(char *str);//将str串以标识符插入符号表,并返回符号表指针
int  InsertConst(char *str);            //将str串以常数插入符号表,并返回常数表指针
bool wordAnalyse(pDualistic pDu);    //词法分析 true正常
//end

//预处理 将缓冲区内的源代码去掉注释和无效空格【所谓的无效空格是指出现在非字符串
//       常量中的空格】
void pretreatment()       //预处理
{int lines=0;
    char tmp[PRO_MAX_LEN];    //先将处理结果保存到临时空间,这样虽然浪费空间但是节约
                            //时间
    int tmpp = 0;    //这个临时空间的末尾指针
    bool flg;
    char tmpc;
    //去掉注释先
    //注释有两种 一种是C++风格的// 另一种是C风格的/**/
    point = 0;
    do
    {
        flg = GetChar();

        if(ch == '/')
        {
            flg = GetChar();
            switch(ch)         // case "/"and "*"
            {
            case '/':
                do
                {
                    flg = GetChar();                    
                }while(!(ch == '\n' || flg == false));// || ch == '\0'));//注释一直到行尾或文件结束
                if(ch == '\n')
                    Retract();    //归还换行函数
                break;
            case '*':
                do
                {
                    flg = GetChar();
                    tmpc = ch;
                    //为了保证出错处理程序能正确定位出错位置 保留注释中的换行
                    if(tmpc == '\n')
                        tmp[tmpp++] = tmpc;
                    flg = GetChar();
                    Retract();    //归还一个字符函数
                }while(flg && !(flg && tmpc == '*' && ch == '/'));   //不以*/
                flg = GetChar();
                if (!flg)
                {
                    ProcError(5);    //错误调用函数  5"注释丢失'
                }
                break;
            default:
                //不是任何一种注释
                Retract(); //将搜索指示器回调一个字符位置
                Retract(); //将搜索指示器回调一个字符位置      “//”或“*/”
                GetChar(); //获得一个字符不包括结束标记
                tmp[tmpp++] = ch;
                flg = GetChar();
                tmp[tmpp++] = ch;   //tmpp临时空间的末尾指针
            }
        }
        else
        {
            tmp[tmpp++] = ch;
        }
    }while(flg);                  //flg布尔变量,判断是否取得字符
    tmp[tmpp] = '\0';
    strcpy(proBuffer,tmp);           // 新取得的字符送入缓冲区
}


void ProcError(int id)  //错误
{
    printf("\nError:第%d行,%s\n",errorLine, errorTab[id]);//errorTab[id]错误列表
}


bool GetChar()//获得一个字符不包括结束标记
{
    if(point < PRO_MAX_LEN && proBuffer[point] != '\0')
    {//如果当前下标合法且当前字符为结束标记则取字符增游标
        ch = proBuffer[point++];
        if (ch == '\n')
            errorLine ++;
        return true;
    }
    ch = '\0';
    return false;
}


bool GetBC()//获得一个非空白字符
{
    do
    {
        if(!GetChar())    //获取字符失败
        {
            ch = '\0';
            return false;
        }
    }while(isspace(ch));    //直到获得一个非空白字符 //isspace(ch)判断字符ch是否为空白符
    return true;
}

void Concat(char *str) //将ch连接到str后
{
    int i;
    for(i=0; str[i]; ++i);
    str[i] = ch;
    str[i+1] = '\0';
}


int Reserve(char *str)//对str字符串查找保留字表 若是一个保留字-返回其编码 否则返回0
{
    int i;
    for(i=0; i<KEYWORD_LEN; ++i)    //从保留字表中查找str串
    {
        if(0 == strcmp(kwTab[i], str))
            return i+1;    //注意,这里加一原因是0值被错误标记占用
    }
    return 0;
}

void Retract()///char *ch//将搜索指示器回调一个字符位置

{ 
    if(proBuffer[point] == '\n' && errorLine > 0)
        errorLine --;
    point --;
}


int InsertId(char *str)//将str串以标识符插入符号表,并返回符号表指针
{
    int i;
    for(i=0; i < pointSTB; ++i) // pointSTB符号表指针
        if(0 == strcmp(signTab[i], str))
            return i;
    strcpy(signTab[pointSTB++], str);
    return (pointSTB-1);
}

int InsertConst(char *str)//将str串以常数插入常量表,并返回常数表指针

{
    int i;
    for(i=0; i < pointCTB; ++i)    //pointCTB常数表指针
        if(0 == strcmp(constTab[i], str))
            return i;
    strcpy(constTab[pointCTB++], str);
    return (pointCTB-1);
}

//词法分析 false--分析结束
bool wordAnalyse(pDualistic pDu)       //词法分析 true正常
{
    int  code, value;
    char judge;    //这里有个技巧 借用此变量巧妙的运用SWITCH结构
    int  i = 0;    //辅助

    GetBC();        //获得一个非空白字符
    judge = ch;
    if (isalpha(ch) || ch == '_')    judge='L';
    //isalpha(ch)如果ch的内容为字母表中的字母,本函数返回非零值,否则返回零值。
    if (isdigit(ch)) judge='D';
	//(isdigit(ch)判断一个字符是否为数字(0-9),是数字返回1,不是返回0		
    switch(judge)
    {
    case 'L':
        while(isalnum(ch) || ch == '_')
			//isalnum(ch)如果本函数的变元为字母或数字,它将返回非零值,否则返回零值。

        {    //标识符
            wordget[i++] = ch;
            GetChar(); //获得一个字符不包括结束标记
        }
        wordget[i] = '\0';
        Retract();    //回退一个字符
        code = Reserve(wordget); //对str字符串查找保留字表 若是一个保留字-返回其编码 否则返回0
        if(code == 0)
        {
            value = InsertId(wordget);//将str串以标识符插入符号表,并返回符号表指针
            pDu->kind  = ID;
            pDu->value = value;
        }
        else
        {
            pDu->kind = code;
            pDu->value = -1;
        }
        return true;
    case 'D':
        while(isdigit(ch))    //isdigit(ch)判断字符ch是否为数字(0-9),是数字返回1,不是返回0;
        {
            wordget[i++] = ch;
            GetChar(); //获得一个字符不包括结束标记
        }
        wordget[i] = '\0';
        Retract(); //回退一个字符
        value = InsertConst(wordget);//将str串以常数插入符号表,并返回常数表指针
        pDu->kind = CONST;
        pDu->value= value;
        return true;
//( ) [ ] . , !  != ~ sizeof < << <= > >> >= = ==  & && &= | || |= ?: + ++ +=
// - -> -- -= * *= / /= % %= >>= <<= ^ ^=
    case '"':
        //字符串常量
        do
        {
            wordget[i++] = ch;
            GetChar();
        }while(ch != '"' && ch != '\0');
        wordget[i++] = ch;    wordget[i] = '\0';
        if(ch == '\0')
        {
            printf("%s",wordget);
            ProcError(3);
            pDu->kind = ERROR;
            pDu->value = 0;
        }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -