实验二 词法分析器的实现

这里定义了一个编程语言称作C-M i n u s (或简称为C-),这是一种适合编译器设计方案的
语言,它比T I N Y语言更复杂,包括函数和数组。本质上它是C的一个子集,但省去了一些重要
的部分,因此得名。这个附录由5小节组成。首先,我们列出了语言惯用的词法,包括语言标
记的描述。其次,给出了每个语言构造的B N F描述,同时还有相关语义的英语描述。在A . 3节,
给出了C-的两个示例程序。再者,描述了C-的一个Tiny Machine运行时环境。最后一节描述
了一些使用C-和T M的编程设计方案,适合于一个编译器教程。

C-惯用的词法

  1. 下面是语言的关键字:
 else if int return void while

所有的关键字都是保留字,并且必须是小写。
2. 下面是专用符号:

+ - * / < <= > >= == != = ; , ( ) [ ] { } /* */
  1. 其他标记是I D和N U M,通过下列正则表达式定义:
ID = letter letter*
NUM = digit digit*
letter = a|..|z|A|..|Z
digit = 0|..|9

小写和大写字母是有区别的。
4. 空格由空白、换行符和制表符组成。空格通常被忽略,除了它必须分开I D、N U M关键字。
5. 注释用通常的C语言符号/ * … * /围起来。注释可以放在任何空白出现的位置(即注释不能放在标记内)上,且可以超过一行。注释不能嵌套。

词法分析器的DFA:

这里写图片描述

源码实现:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<iostream>
#define intputfile "test.c"
#define outputfile "target.c"
typedef int sInt;
using namespace std;

FILE *source;
FILE *target;

long beginp[5];   //记录文件指针的开始位置
long endp[5];    //记录文件指针的结束位置
char idStr[80]="";   //保存标识符中间值
int state[5]={0}; //不同记号类型的状态
char unaryOP[16]={'+','-','*','/','<','>','=',';',',','(',')','[',']','{','}','!'}; //保存一元运算符
char *p[6]={"if","else","int","return","void","while"};  //系统保留字
char *strToken[7]={"ID","NUM","OP","FUCN","RESW","ERROR","COM"};
typedef enum {ID,NUM,OP,FUCN,RESW,ERROR,COM}tokenType; //记号类型

void clearState()
{
    memset(state,0,sizeof(state));
    memset(idStr,'\0',sizeof(idStr));
    memset(beginp,0,sizeof(beginp));
    memset(endp,0,sizeof(endp));
}

void strPrintf(long begin,long end,tokenType t)
{
    bool isComment = false;
    int k;
    char s[200]="";
    long len=end-begin;
    fseek(source,-len,1);//文件指针回退
    for(int i=0;i<len;i++) s[i]=fgetc(source);
    switch(t)
    {
        case ID:
        k=0;break;
        case NUM:
        k=1;break;
        case OP:
        k=2;break;
        case FUCN:
        k=3;break;
        case RESW:
        k=4;break;
        case ERROR:
        k=5;break;
        case COM:
        k=6;
        isComment=true;break;
        default:cout<<"输入有误!\n";
    }
    //printf("%s\n",s);
    if(isComment)
    {
        fprintf(target,"%s\n",s);
        printf("%s\n",s);
    }

    else
    {
        fprintf(target,"<%s,%s>\n",strToken[k],s);
        printf("<%s,%s>\n",strToken[k],s);
    }
}

void unaryPrintf(char s,tokenType t)
{
    int k;
    switch(t)
    {
        case ID:
        k=0;break;
        case NUM:
        k=1;break;
        case OP:
        k=2;break;
        case FUCN:
        k=3;break;
        case RESW:
        k=4;break;
        case ERROR:
        k=5;break;
        case COM:
        k=6;break;
        default:cout<<"输入有误!\n";
    }
    //cout<<strToken[k]<<endl;
    fprintf(target,"<%s,%c>\n",strToken[k],s);
    printf("<%s,%c>\n",strToken[k],s);
}

bool isOperator(char ch)
{
    for(int i=0;i<16;i++)
    {
        if( ch==unaryOP[i] )
        return true;
    }
    return false;
}
void number(char ch,int i)
{
    beginp[i]=ftell(source)-1;
    while(!feof(source))
    {
        if(ch>='0' && ch<='9')
        {
            state[i]=1;
            endp[i]=ftell(source);
        }else
        {
            fseek(source,-1L,1); //回退,读到了下一个字符
            strPrintf(beginp[i],endp[i],NUM);
            return;
        }
        ch = fgetc(source);
    }
}
void comment(char ch,int i)
{
    bool isexit = false; //当不是注释时用于跳出循环
    while(!feof(source))
    {
        switch(state[i])
        {
            case 0:
            if(ch=='/')
            {
                state[i]=1;
                beginp[i]=ftell(source)-1;
            }
            break;
            case 1:
            if(ch=='*')
            {
                state[i]=2;
            }
            else
            {
                isexit = true; //说明不是注释,请求退出
                unaryPrintf('/',OP);
                fseek(source,-1L,1); //回退一个字节,因为向后判断移了一位
            }
            break;
            case 2:
            if(ch=='*')
            {
                state[i]=3;
            }else
            {
                state[i]=2;
            }
            break;
            case 3:
            if(ch=='/')
            {
                state[i]=4;
                endp[i]= ftell(source);
                strPrintf( beginp[i],endp[i],COM);
                isexit = true;                               //back
            }else state[i]=2;
            break;
        }
        if(isexit) return;//back;
        ch = fgetc(source);
    }
}


void myOperator(char ch,int i)
{
    bool isReturn = false;
    while(!feof(source))
    {
        if(ch=='+' ||ch=='-'||ch=='*'||ch==';'||ch==','||ch=='('||ch==')'||ch=='['||ch==']'||ch=='{'||ch=='}')
        {
            state[i]=1;
            unaryPrintf(ch,OP);
            isReturn = true;
        }else
        {
            switch(state[i])
            {
                case 0:
                beginp[i]=ftell(source)-1;
                switch(ch)
                {
                    case '<':
                    state[i]=2;
                    break;
                    case '>':
                    state[i]=4;
                    break;
                    case '=':
                    state[i]=6;
                    break;
                    case '!':
                    state[i]=8;
                    break;
                    default:cout<<"data error!\n";
                }
                break;
                case 2:
                if(ch=='=')
                {
                    state[i]=3;
                    endp[i]=ftell(source);
                    strPrintf(beginp[i],endp[i],OP);
                    isReturn = true;
                }else
                {
                    //属于一元操作符
                    state[i]=2;
                    fseek(source,-1L,1);//回退一个字符
                    unaryPrintf('<',OP);
                    isReturn = true;
                }
                break;
                case 4:
                if(ch=='=')
                {
                    state[i]=5;
                    endp[i]=ftell(source);
                    strPrintf(beginp[i],endp[i],OP);
                    isReturn = true;
                }else
                {
                    //属于一元操作符
                    state[i]=4;
                    fseek(source,-1L,1);//回退一个字符
                    unaryPrintf('>',OP);
                    isReturn = true;
                }
                break;
                case 6:
                if(ch=='=')
                {
                    state[i]=7;
                    endp[i]=ftell(source);
                    strPrintf(beginp[i],endp[i],OP);
                    isReturn = true;
                }else
                {
                    //属于一元操作符
                    state[i]=6;
                    fseek(source,-1L,1);//回退一个字符
                    unaryPrintf('=',OP);
                    isReturn = true;
                }
                break;
                case 8:
                if(ch=='=')
                {
                    state[i]=9;
                    endp[i]=ftell(source);
                    strPrintf(beginp[i],endp[i],OP);
                    isReturn = true;
                }else
                {
                    //属于一元操作符
                    state[i]=8;
                    fseek(source,-1L,1);//回退一个字符
                    unaryPrintf('!',OP);
                    isReturn = true;
                }
                break;
                default:cout<<"data error!\n";
            }
        }
        if(isReturn) return;
        ch = fgetc(source);
    }
}
bool isLiter(char ch)
{
    if((ch>='A' && ch<='Z')||( ch>= 'a' && ch<='z') || ch=='_')
    {
        return true;
    }else
    return false;
}

bool isResw(char *s)
{
    for(int i=0;i<6;i++)
    {
        if( strcmp(s,p[i])==0 )
        return true;
    }
    return false;
}

void identifier(char ch,int i)
{
    beginp[i] = ftell(source)-1;
    long len =0;
    bool isQuit = false;
    bool isFucn = false;
    while(!feof(source))
    {
        if( isLiter(ch) )
        {
            state[i]=1;
            endp[i]=ftell(source);
        }
        else
        {
            long enter = 1; //
            isQuit = true;
            if(ch=='\n') enter = 2;
            fseek(source,-enter,1); //回退一或2个字符
            //cout<<"pos="<<ftell(source)<<endl;
            //printf("%d %d\n",beginp[i],endp[i]);
            len = endp[i]-beginp[i];
            fseek(source,-len,1);
            //cout<<"pos="<<ftell(source)<<endl;
            for(int j=0;j<len;j++)
            {
                idStr[j] = fgetc(source);

            }
            if( isResw(idStr) ) //如果是保留字,就保存退出
            {
                strPrintf(beginp[i],endp[i],RESW);

            }else
            {
                char temps;
                long cout=1;
                temps = fgetc(source);
                while(!feof(source))
                {
                    if(temps==' ' ||temps=='\n' || temps=='\t')
                    {
                        ; //jump it;
                    }else
                    {
                        if(temps=='(')
                           {
                               isFucn = true; //表明是函数名
                               break;
                           }
                        else
                           {
                               isFucn = false; //不是函数名
                               break;
                           }
                    }
                    temps = fgetc(source);
                    cout++;
                }
                fseek(source,-cout,1); //回退文件指针
                //printf("back=%ld\n",ftell(source));
                if(isFucn)
                {
                    strPrintf(beginp[i],endp[i],FUCN);
                }else
                {
                    strPrintf(beginp[i],endp[i],ID);
                }
            }
        }
        if(isQuit) return;
        ch = fgetc(source);
    }
}

void Scanner()
{
    char ch=fgetc(source);
    while( !feof(source) )
    {
        if(ch==' ' ||ch=='\n' || ch=='\t')
        {
            ;//nothing jump it!
        }else if(ch=='/')
        {
            comment(ch,0);
            clearState(); //清楚状态信息
        }else if(ch>='0'&&ch<='9')
        {
            number(ch,1); //处理数字
            clearState();
        }else if( isOperator(ch) )
        {
            myOperator(ch,2); //处理操作符
            clearState();
        }else if( isLiter(ch) )
        {
            identifier(ch,3); //处理标志符
            clearState();
        }
        else
        {
            unaryPrintf(ch,ERROR);
        }
        ch = fgetc(source);
    }
}

bool read(){
   if(((source=fopen(intputfile,"r"))==NULL)||((target=fopen(outputfile,"w"))==NULL))
    return 0;
    return 1;
}
int main()
{
    if(!read()){
        printf("文件打开失败!");
        exit(0);
    }
    Scanner();  //开始扫描文件 entrance
    fclose(source);
    fclose(target);
    return 0;
}


输入文件:

int gcd (int u, int v)
{
    if (v == 0)
        return u ;
    else
        return gcd(v,u-u/v*v);
    /* u-u/v*v == u mod v */
}

void main(void)
{
    int x;int y;
    x = input();
    y = input();
    output(gcd(x,y));
}

输出文件:

<RESW,int>
<FUCN,gcd>
<OP,(>
<RESW,int>
<ID,u>
<OP,,>
<RESW,int>
<ID,v>
<OP,)>
<OP,{>
<RESW,if>
<OP,(>
<ID,v>
<OP,==>
<NUM,0>
<OP,)>
<RESW,return>
<ID,u>
<OP,;>
<RESW,else>
<RESW,return>
<FUCN,gcd>
<OP,(>
<ID,v>
<OP,,>
<ID,u>
<OP,->
<ID,u>
<OP,/>
<ID,v>
<OP,*>
<ID,v>
<OP,)>
<OP,;>
/* u-u/v*v == u mod v */
<OP,}>
<RESW,void>
<FUCN,main>
<OP,(>
<RESW,void>
<OP,)>
<OP,{>
<RESW,int>
<ID,x>
<OP,;>
<RESW,int>
<ID,y>
<OP,;>
<ID,x>
<OP,=>
<FUCN,input>
<OP,(>
<OP,)>
<OP,;>
<ID,y>
<OP,=>
<FUCN,input>
<OP,(>
<OP,)>
<OP,;>
<FUCN,output>
<OP,(>
<FUCN,gcd>
<OP,(>
<ID,x>
<OP,,>
<ID,y>
<OP,)>
<OP,)>
<OP,;>
<OP,}>
  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

计算机的小粽子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值