title: 简单词法分析器的实现
date: 2018-10-08 23:15:26
updated: 2018-10-08 23:15:26
description: 简单词法分析器的实现_编译原理实现
categories: 必修
photo:
tags:
- 编译原理
music-id: 415793869
password:
math:
一.实验题目
用C或C++语言编写一个简单的词法分析程序,扫描C语言小子集的源程序,根据给定的词法规则,识别单词,填写相应的表。如果产生词法错误,则显示错误信息、位置,并试图从错误中恢复。简单的恢复方法是忽略该字符(或单词)重新开始扫描。
二.词法分析规则:
<标识符>::=<字母>
<标识符>::=<标识符><字母>
<标识符>::=<标识符><数字>
<无符号整数>::=<数字>
<无符号整数>::=<数字序列><数字>
<数字序列>::=<数字序列><数字>
<数字序列>::=<数字>
<字母>::=a|b|c|……|x|y|z
<数字>::=0|1|2|3|4|5|6|7|8|9
<加法运算符>::=+|-
<乘法运算符>::=*|/
<关系运算符>::=<|>|!=|>=|<=|==
<分界符>::=,|;|(|)|{|}
<保留字>::=main|int|if|else|while|do
三.实现任务
1.根据给定的词法规则,识别单词,填写相应的表。
2.忽略空白字符,注释
3.产生词法错误时,显示错误信息、位置,并试图从错误中恢复。
四.实现流程
1.读到空格则略过,读下一个字符;若读到的是字母,就再接着读,直到读到的既不是字母也不是数字也不是下划线,并将读到的写入到token数组;
2.若读到的是数字,直到读到的不是数字或小数点,将读到的写入到token数组;
3.若读到的是<|>|=,则再读入下一位,若为=,则该运算符为<=|>=|==,若为其他字符,则返回<|>|=的种别码;若读到的是/,则读下一位,若为*,则说明之后为注释内容,一直读入直到读入*,并判断下一位是否为/,若是则注释结束,不是继续往下一位读入;若读入\n,则行数加一,若读入的字符与以上都不匹配,则报错,并输出出错行数。
五.种别码:
单词符号 | 种别码 | 单词符号 | 种别码 |
---|---|---|---|
# | 0 | + | 18 |
Num | 1 | - | 19 |
Letter | 2 | * | 20 |
main | 3 | / | 21 |
if | 4 | = | 22 |
else | 5 | > | 23 |
do | 6 | >= | 24 |
while | 7 | < | 25 |
for | 8 | <= | 26 |
swtich | 9 | ; | 27 |
case | 10 | " | 28 |
int | 11 | ++ | 29 |
double | 12 | – | 30 |
float | 13 | /* | 31 |
long | 14 | */ | 32 |
void | 15 | { | 33 |
( | 16 | } | 34 |
) | 17 |
六.代码实现
#include<bits/stdc++.h>
using namespace std;
const int max_word = 505;
char token[12];
char in[105];
FILE *fin,*fout;
int cnt = 0,token_num = 0;
int row = 1;
int flag = 0;
char ch;
//关键字
const char keyWord[13][20] = {"main","if","else","do","while","for","switch",
"case","int","double","float","long","void"};
void init_token(){
int i;
for(i = 0;i < 12;i++){
token[i] = NULL;
}
}
int judge_token(){
init_token();
if(flag == 0){
ch = getc(fin);
}
flag = 1;
while(ch == ' ' || ch == '\t' || ch == '\n'){
if(ch == '\n'){
row++;
}
ch=getc(fin);
}
token_num = 0;
if((ch>='a' && ch <= 'z') || (ch >= 'A' &&ch <= 'Z')){
//可能为标识符或者变量名
while((ch>='a' && ch <= 'z') || (ch >= 'A' &&ch <= 'Z') || (ch >= '0' && ch <= '9')){
token[token_num++] = ch;
ch = getc(fin);
}
token[token_num++] = '\0';
for(int i = 0;i <13;i++){
if(strcmp(token,keyWord[i]) == 0){
//3为关键词
return 3;
}
}
//2为标识符
return 2;
}
//是数字
else if(ch >= '0' && ch <= '9'){
while((ch >= '0'&& ch <= '9') || ch == '.'){
token[token_num++] = ch;
ch = getc(fin);
}
return 1;
}
else{
token[token_num++] = ch;
switch(ch){
case '(': ch = getc(fin); return 16;
case ')': ch = getc(fin); return 17;
case '{': ch = getc(fin); return 33;
case '}': ch = getc(fin); return 34;
case '+':
ch = getc(fin);
if(ch == '+'){
token[token_num++] = ch;
ch = getc(fin);
return 29;
}
else{
return 18;
}
case '-':
ch = getc(fin);
if(ch == '-'){
token[token_num++] = ch;
ch = getc(fin);
return 30;
}
else{
return 19;
}
case '*':
ch = getc(fin);
if(ch == '/'){
token[token_num++] = ch;
ch = getc(fin);
return 32;
}
else{
return 20;
}
case '/':
ch = getc(fin);
if(ch == '*'){
token[token_num++] = ch;
ch = getc(fin);
return 31;
}
else{
return 21;
}
//这里要重新编码
case '=':
ch = getc(fin);
if(ch == '='){
token[token_num++] = ch;
ch = getc(fin);
return 23;
}
else{
return 22;
}
case '>':
ch = getc(fin);
if(ch == '='){
token[token_num++] = ch;
ch = getc(fin);
return 24;
}
else{
return 23;
}
case '<':
ch = getc(fin);
if(ch == '='){
token[token_num++] = ch;
ch = getc(fin);
return 26;
}
else{
return 25;
}
case ';': ch = getc(fin); return 27;
case '"': ch = getc(fin); return 28;
case '!':
ch = getc(fin);
if(ch == '='){
token[token_num++] = ch;
ch = getc(fin);
return 37;
}
else{
return 36;
}
case '#': ch = getc(fin); return -2;
case ',': ch = getc(fin); return 35;
case EOF: return -1;
default: ch = getc(fin); return -10;
}
}
}
void getWord(){
int temp;
while(1){
temp = judge_token();
if(temp==-1){
break;
}
switch(temp){
case -10:
cout<<"第 "<<row<<" 行出现错误."<<endl;
break;
default:
cout<<"<"<<temp<<","<<token<<">"<<endl;
break;
}
}
}
int main(){
fin = fopen("compiler.txt","r");
getWord();
return 0;
}
七.样例结果
样例:
结果: