当前位置:   article > 正文

编译原理:词法分析的简单代码实现_(1) 关键字: for if then else while do (所有关键字都是小写) (2)

(1) 关键字: for if then else while do (所有关键字都是小写) (2) 运算符和分隔

词法分析:字符流转换为记号流

问题描述:对循环语句和条件判断语句编写词法分析编译程序,只能通过一遍扫描完成。

要求:
(1)关键字: for if then else while do until int input output,所有关键字都是小写。
(2)运算符和分隔符: : = + - * / < > <= <> >= ; ( ) #
(3)其他标识符(ID)和整型常数(NUM),通过以下模式定义:
ID=letter(letter | digit)*
NUM=digit digit*
(4)空格由空白、制表符和换行符组成。空格一般用来分隔ID、NUM、运算符、分隔符和关键字,词法分析阶段通常被忽略。

词法单元和词法记号的对应关系
这里写图片描述

程序功能:
输入:源程序
输出:二元组(词法记号,属性值/其在符号表中的位置)构成的序列。

样例:
输入:int x:=5;
输出:(30, int)(10,’x’)(18, :=) (11,5) (26, ;)

状态转换图:
这里写图片描述
注:0为初态,2,3,4,6,11,12,13为非确定终态,1,5,7,8,9,10为确定终态
非确定终态:这里表示当前子串还不能确定作为一个词法单元
确定终态:这里表示当前终态可以确定作为一个词法单元
非确定终态的其它未标明输入,皆指向1

#include<iostream>
using namespace std;
int main()
{
    void fun(char*a);
    char a[100]={};//保存用户输入,
    //接收输入,不要超过100个字符,否则getline会设置失效位,
    //(如果有的话)接下来的输入将被阻断,需要的话,可以调用cin.clear()恢复输入
    cin.getline(a,100);//遇见回车表示输入结束
    fun(a);
    cout<<endl<<endl<<endl;
    return 0;
}
void fun(char* a)//功能函数
{
    int mov(int im,char c);
    void output(int i,string s);
    string s=a;//将用户输入转换为string类型,因为string.substr比较好用,接下来就会看到
    string keyWord[]={"for","if","then","else","while","do","until","int","input","output"};//关键字
    int kwLenth=sizeof(keyWord)/sizeof(string);//keyWord数组的元素个数
    int tokenKw[]={1,2,3,4,5,6,29,30,31,32};//关键字对应的记号
    int last=0;//待操作终止位,包括这一位
    int start=0;//待操作起始位
    int im=0;//move函数的输入,input_of_move的缩写
    int om=1;//move函数的输出,output_of_move的缩写
    string sub="";//保存当前有效字串
    for(last=0;last<s.size();++last)//扫描输入的源程序
    {
        if(int(s[last])==32||int(s[last])==9)//遇见空格或者水平制表符
        {//(程序中一般不会用水平制表符作为分隔符,为程序完整起见,这里加上了对水平制表符的判断)
            start++;
            //im=0;
            continue;
        }
        sub=s.substr(start,last+1-start);//第一个参数是起始位置,第二个参数是偏移量
        om=mov(im,s[last]);//调用mov函数
        int kw=0;
        switch(om)
        {
        case 1://应该用im对应的终态,即上一个终态
            sub=s.substr(start,last-start);//第一个参数是起始位置,第二个参数是偏移量
            output(im,sub);//输出记号流
            start=last;//移动待操作起始位
            last--;//使得下一轮循环重新读取当前字符
            im=0;//对im置0,因为将要寻找下一个词法单元
            break;
        case 5://单个运算符或分隔符对应的终态
            output(5,sub);
            start=last+1;
            im=0;
            break;
        case 7://<>对应的终态
            output(7,sub);
            start=last+1;
            im=0;
            break;
        case 8://<=对应的终态
            output(8,sub);
            start=last+1;
            im=0;
            break;
        case 9://>=对应的终态
            output(9,sub);
            start=last+1;
            im=0;
            break;
        case 10://:=对应的终态
            output(10,sub);
            start=last+1;
            im=0;
            break;
        case 12://可能是关键字
            for(kw=0;kw<kwLenth;++kw)
            {
                if(sub==keyWord[kw])
                    break;
            }
            if(kw<kwLenth)//匹配关键字成功
            {
                cout<<" ("<<tokenKw[kw]<<","<<sub<<")";
                start=last+1;
                im=0;
            }
            else
                im=om;//不确定终态,还未找到词法单元
            break;
        default://其它值不能确定是终态,除非当前是最后一个字符
            if(last==s.size()-1)
            {
                output(om,sub);
            }
            else
                im=om;//不确定终态,还未找到词法单元
        }
    }
}
int mov(int im,char c)//move函数,需要结合状态转换图理解
{
    int asc=(int)c;//获取当前字符的ASCLL码
    int om=0;//保存mov函数的输出,将作为返回值
    switch(im)
    {
    case 0://从0开始
        if(asc>=48&&asc<=57)//遇见数字
            om=6;
        else if(asc>=65&&asc<=90||asc>=97&&asc<=122)//遇见字母
            om=11;
        else//遇见运算符或分隔符
        {
            if(c=='<')
                om=2;
            else if(c=='>')
                om=3;
            else if(c==':')
                om=4;
            else//遇见其它运算符或分隔符
                om=5;
        }
        break;
    case 2:
        if(c=='>')//表示<>
            om=7;
        else if(c=='=')//表示<=
            om=8;
        else
            om=1;//表示im
        break;
    case 3:
        if(c=='=')//表示>=
            om=9;
        else
            om=1;
        break;
    case 4:
        if(c=='=')//表示:=
            om=10;
        else
            om=1;
        break;
    case 6:
        if(asc>=48&&asc<=57)//遇见数字
            om=6;
        else
            om=1;
        break;
    case 11:
        if(asc>=65&&asc<=90||asc>=97&&asc<=122)//遇见字母
            om=12;
        else if(asc>=48&&asc<=57)//遇见数字
            om=13;
        else
            om=1;
        break;
    case 12:
        if(asc>=65&&asc<=90||asc>=97&&asc<=122)//遇见字母
            om=12;
        else if(asc>=48&&asc<=57)//遇见数字
            om=13;
        else
            om=1;
        break;
    case 13:
        if(asc>=48&&asc<=57)//遇见数字
            om=13;
        else
            om=1;
    default:
        ;
    }
    return om;
}
void output(int i,string s)//输入一个数字和当前有效子串,输出其对应的词法单元的记号流
{
    int trans(char c);
    switch(i)
    {
    case 2://表示<,是单个字符
        ;
    case 3://表示>,是单个字符
        ;
    case 4://表示:,是单个字符
        ;
    case 5://表示单个的运算符或分隔符
        cout<<" ("<<trans(s[0])<<","<<s<<")";
        break;
    case 6://表示数字
        cout<<" (11,"<<s<<")";
        break;
    case 7://表示<>
        cout<<" (21,<>)";
        break;
    case 8://表示<=
        cout<<" (22,<)";
        break;
    case 9://表示>=
        cout<<" (24,<)";
        break;
    case 10://表示:=
        cout<<" (18,:=)";
        break;
    case 11://表示id
       ;
    case 12://表示id
        ;
    case 13://表示id
        cout<<" (10,"<<s<<")";
        break;
    default:
        ;
    }
}
int trans(char c)//输入一个单运算符或分隔符,返回对应的词法记号,需要结合表格理解
{
    int token=0;
    switch(c)
    {
    case ':':
        token=17;
        break;
    case '=':
        token=25;
        break;
    case '+':
        token=13;
        break;
    case '-':
        token=14;
        break;
    case '*':
        token=15;
        break;
    case '/':
        token=16;
        break;
    case '<':
        token=20;
        break;
    case '>':
        token=23;
        break;
    case ';':
        token=26;
        break;
    case '(':
        token=27;
        break;
    case ')':
        token=28;
        break;
    case '#':
        token=0;
        break;
    default:
        ;
    }
    return token;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258

运行结果:
这里写图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/294214
推荐阅读
相关标签
  

闽ICP备14008679号