实验一 源程序的预处理及词法分析程序的设计与实现
使用方法:主程序的代码放到一个主程序cpp文件里,其他代码放到.h文件夹里,不知道如何建立头文件可以查看我的其他博客
一、实验目的
设计并实现一个包含预处理功能的词法分析程序,加深对编译中词法分析过程的理解。
二、 实验要求
1、实现预处理功能
源程序中可能包含有对程序执行无意义的符号,要求将其剔除。
首先编制一个源程序的输入过程,从键盘、文件或文本框输入若干行语句,依次存入输入缓冲区(字符型数据);然后编制一个预处理子程序,去掉输入串中的回车符、换行符和跳格符等编辑性文字;把多个空白符合并为一个;去掉注释。
2、实现词法分析功能
输入:所给文法的源程序字符串。
输出:二元组(syn,token或sum)构成的序列。其中,
syn为单词种别码。
Token为存放的单词自身字符串。
Sum为整型常量。
具体实现时,可以将单词的二元组用结构进行处理。
3、待分析的C语言子集的词法(可以自行扩充,也可以按照C语言的词法定义)
1)关键字
main if then while do static int double struct break else long switch case typedef char return const float short continue for void default sizeof do
所有的关键字都是小写。
2)运算符和界符
-
-
- / : := < <> <= > >= = ; ( ) #
3)其他标记ID和NUM
通过以下正规式定义其他标记:
ID→letter(letter|digit)*
NUM→digit digit*
letter→a|…|z|A|…|Z
digit→0|…|9…
4)空格由空白、制表符和换行符组成
空格一般用来分隔ID、NUM、专用符号和关键字,词法分析阶段通常被忽略。
4、各种单词符号对应的种别码
表1 各种单词符号的种别码
单词符号 种别码 单词符号 种别码
main 1 ; 41 浮点数 44
if 2 ( 42 十六进制数 45
then 3 ) 43 || 46
while 4 int 7 && 47
do 5 double 8 | 48
static 6 struct 9 & 49
ID 25 break 10 constant char 53
NUM 26 else 11 constant str 54
- / : := < <> <= > >= = ; ( ) #
-
-
27 long 12
-
28 switch 13
-
29 case 14
- / 30 typedef 15
-
31 char 16
:= 32 return 17
< 33 const 18
<> 34 float 19
<= 35 short 20
36 continue 21
= 37 for 22
= 38 void 23
default 39 sizeof 24
do 40 # 0
5、 词法分析程序的主要算法思想
算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到的单词符号的第一个字符的种类,拼出相应的单词符号。
源码
主程序实现实验报告上的内容(包含字符串识别)
#include<bits/stdc++.h>
using namespace std;
#define N 1000
#include <ctype.h>
#include"is16H.h"
#include"isfloat.h"
#include"ischar.h"
#include"predo.h"
int len,i=0,j=0;
char* keyword[27]= {"","main","if","then","while","continue",
"static","int","double","struct","break","else","long",
"switch","case","typedef","char","return","const","float",
"short","continue","for","void","sizeof","default","do"
};
int LA(FILE *p) {
char str[N],c;
int syn,sum;
int k;
char token[200]; //获取以空格分开的每个词
//获取字符串
while((c=getc(p))!=EOF) {
str[i] = c;
i++;
}
str[i] = '\0';
//创建结果文件
if((p=fopen(".\\test2.txt","w"))==NULL) {
printf("创建文件失败");
return 0;
}
//词法分析
for(i=0; str[i]!='\0';) {
j = 0;
sum = -1;//表示没有遇见数字
//标识符处理
if((str[i]>='a'&&str[i]<='z')||(str[i]>='A'&&str[i]<='Z')) {
while((str[i]>='a'&&str[i]<='z')||(str[i]>='A'&&str[i]<='Z')||(str[i]>='0'&&str[i]<='9')||str[i]=='_') {
token[j] = str[i];
j++;
i++;
}
token[j] = '\0';
for( k=1; k<27; k++) {
if(strcmp(keyword[k],token)==0)
break;
}
if(k<25)
syn = k;
else if(k==25)
syn = 39; //default关键字在种别码表中是39
else if(k==26)
syn = 40; //do关键字对应种别码40
else syn = 25; //在非关键字数组中的就是用户自定义标识符
}
//数字处理
else if(str[i]>='0'&&str[i]<='9')
{
sum=0;
while(str[i]>='0'&&str[i]<='9') { //当读到第一个为0~9的数字时接着读之后的数字
sum = sum*10+str[i]-'0'; //把字符转化成数字
token[j] = str[i];
j++;
i++;
}
int starti=i;int startj=j;
int k=0;
if((str[i]=='.'||str[i]=='e'))//假设它是浮点数
{
k=1;
k = isfloat(str,token,i,j);//不能传表达式
if(k==0)
{
i=starti;//回退,把.或者e分给别的分析器
j=startj;
}
else {
syn=44;
sum=-1;}
}
if(k==0&&((str[i]>='a'&&c<='f')||(str[i]>='A'&&c<='F')||(str[i]=='H'||str[i]=='h')))
{
k = is16H(str,token,i,j);
if(k==0)
{
i=starti;//回退,把.或者e分给别的分析器
j=startj;
}
else {
syn=45;
sum=-1;}
}
if(k==0&&(str[i]>='a'&&str[i]<='z')||(str[i]>='A'&&str[i]<='Z')) {
sum=-1;
syn=-3;//类别为出错的标识符
while((str[i]>='a'&&str[i]<='z')||(str[i]>='A'&&str[i]<='Z')||(str[i]>='0'&&str[i]<='9')) {
token[j] = str[i];
j++;
i++;
}
}
if(sum>=0) syn=26;
}
//字符串常量处理
else if(str[i]=='"'){
int starti=i,startj=j;
token[j++]=str[i++];
while(str[i]!='"'&&str[i]!='\0')
{
token[j++]=str[i++];
}
token[j++]=str[i++];
if(str[i-1]=='"')
{
syn=54;
}
else
{
i--;j--;
syn=-5;
}
}
//字符常量处理
else if(str[i]=='\'')
{
int starti=i,startj=j;
int k=ischar(str,token,i,j);
if(k==0)
{
syn=-2;
i=starti;j=startj;
token[j++]=str[i++];
while(str[i]!=' '&&str[i]!='\''&&str[i]!='\0')
token[j++]=str[i++];
token[j++]=str[i++];
if(str[i-1]==' ')
{
i--;j--;//空格不能吸收近去
}
}
else {
syn=53;
}
}
//界符以及运算符处理
else {
if(str[i]==':'&&str[i+1]=='=') {
syn = 32;
token[j++] = str[i++];
token[j++] = str[i++];
} else if(str[i]=='<'&&str[i+1]=='>') {
syn = 34;
token[j++] = str[i++];
token[j++] = str[i++];
} else if(str[i]=='<'&&str[i+1]=='=') {
syn = 35;
token[j++] = str[i++];
token[j++] = str[i++];
} else if(str[i]=='>'&&str[i+1]=='=') {
syn = 36;
token[j++] = str[i++];
token[j++] = str[i++];
} else if(str[i]=='|'&&str[i+1]=='|') {
syn = 46;
token[j++] = str[i++];
token[j++] = str[i++];
} else if(str[i]=='&'&&str[i+1]=='&') {
syn = 47;
token[j++] = str[i++];
token[j++] = str[i++];
} else if(str[i]==' ') {
i++;
syn = -4; //空格不输出
} else {
switch(str[i]) {
case '+':
syn = 27;
break;
case '-':
syn = 28;
break;
case '*':
syn = 29;
break;
case '/':
syn = 30;
break;
case ':':
syn = 31;
break;
case '<':
syn = 33;
break;
case '>':
syn = 36;
break;
case ';':
syn = 41;
break;
case ')':
syn = 43;
break;
case '(':
syn = 42;
break;
case '#':
syn = 0;
break;
case '=':
syn = 38;
break;
case '&':
syn = 48;
break;
case '|':
syn = 49;
break;
case '{':
syn = 50;
break;
case '}':
syn = 51;
break;
default:
syn = -1;
break;
}
token[j++] = str[i++];
}
}
token[j] = '\0';
if(sum!=-1) {
printf("%d %d\n",sum,syn);
fprintf(p,"%d %d\n",sum,syn);
} else if(syn==-1) {
printf("%s error\n",token);
fprintf(p,"%s error\n",token);
} else if(syn==-2) {
printf("%s error char\n",token);
fprintf(p,"%s errorchar\n",token);
} else if(syn == -3) {
printf("%s error ID\n",token);
fprintf(p,"%s error ID\n",token);
} else if(syn == -5) {
printf("%s error str\n",token);
fprintf(p,"%s error str\n",token);
}else if(syn==-4){//空格什么也不输出
}else {
printf("%s %d\n",token,syn);
fprintf(p,"%s %d\n",token,syn);
}
}
fclose(p);
return 0;
}
int main() {
FILE *p;
if((p=fopen(".\\test.txt","r"))==NULL) {
printf("读取源文件失败");
return 0;
}
printf("预处理结果:\n");
formula_str(p);
if((p=fopen(".\\test1.txt","r"))==NULL) {
printf("读取预处理文件失败");
return 0;
}
printf("\n词法分析结果:\n");
LA(p);
fclose(p);
}
判断是不是16进制数
//#include <stdio.h>
//#include <ctype.h>
//#include <string.h>
int is16H(char *argv,char* token,int &i,int &j) {
int state,ERROR=-1;
int starti=i;
int startj=j;
char c; /* 暂时存放所取得的一个字符 */
state=1; /* 初始态为0 */
ERROR=0; /* 控制是否为可识别词or非法字符 */
for(; (c=argv[i])!=' '&&(c=argv[i])!='\0'; i++) {
switch(state) {
case 0:
if(isdigit(c)) state=1;
else if(isalpha(c)) state=2;
else ERROR=1;
break; //ERROR=1,表示当前字符c为非法字符。
case 1:
if(isdigit(c)) state=1;
else if((c>='a'&&c<='f')||(c>='A'&&c<='F')) state=4;
else if(c=='H'||c=='h') state=6;
else ERROR=1;
break;
case 2:
if(isalnum(c)) state=2;
else ERROR=1;
break;
case 4:
if(isdigit(c)||(c>='a'&&c<='f')||(c>='A'&&c<='F')) state=4;
else if(c=='H'||c=='h') state=6;
else ERROR=1;
break;
case 6:
ERROR=1; //到6了说明已经看到h,如果还能再进来说明不是h结尾。
break;
}
if(ERROR==1) break; /* 退出内for的循环,完成一个词的分析。*/
}
if(ERROR==0&&state==6)
{
int k;
for( k=0;k<=i-starti;k++)//k最后也要指向下一个
{
token[j+k]=argv[starti+k];
}
j=j+k-1;
return 1;
}
else
{
return 0;
}
}
//
//int main() {
// char* a="13fgH";
// int x=is16H(a);
// if(x==1) printf("16");
// if(x==0) printf("无法识别");
// return 0;
//}
判断是不是浮点数,包括科学计数法
//#include <stdio.h>
//#include <ctype.h>
//#include <string.h>
int isfloat(char* str,char* token,int &i,int &j)
{
int start=i;
i--;//一开始i已经指向下一个
char c;
int state = 13;
while(1)
{
switch(state){
case 12:
c=str[++i];
if(isdigit(c)){
state = 13;
}else{
i++;
}
break;
case 13:
c=str[++i];
if(isdigit(c))
return 0;
else if(c == 'e'||c == 'E')
state = 16;
else if(c == '.')
state = 14;
else
state = 19;
break;
case 14:
c=str[++i];
if(isdigit(c))
state = 15;
else return 0;
break;
case 15:
c=str[++i];
if(isdigit(c))
state = 15;
else if(c == 'e'|| c == 'E')
state = 16;
else
state = 19;
break;
case 16:
c=str[++i];
if(isdigit(c))
state = 18;
else if(c == '+' || c == '-')
state = 17;
else return 0;
break;
case 17:
c=str[++i];
if(isdigit(c))
state = 18;
else return 0;
break;
case 18:
c=str[++i];
if(isdigit(c))
state = 18;
else
state = 19;
break;
case 19:
int k;
for( k=0;k<=i-start;k++)
{
token[j+k]=str[start+k];
}
j=j+k-1;
return 1;
}
}
}
//int main()
//{
// char *str="122e1";
// char token[20];
// int i=-1;
// int k=isfloat(str,token,i);
// if(k==1)
// printf("%s\n",token);
// else
// printf("error");
// printf("%d",i);
//
//}
判断是不是字符,包括转义字符
//#include <stdio.h>
//#include <ctype.h>
//#include <string.h>
/*
注意字符常量
'''不行 '\''
'\'不行 '\\'
'"'可以
*/
int isteshu(char c)
{
if(c=='n'||c=='r'||c=='t'||c=='v'||c=='a'||c=='b'||c=='f'||c=='\\'||c=='\''||c=='?')
return 1;
else return 0;
}
int ischar(char* str,char* token,int &i,int &j)
{
int start=i;
char c;
int state =2;
while(1)
{
switch(state){
case 1:
c=str[++i];
if(c=='\'') state =2;
else return 0;
break;
case 2:
c=str[++i];
if(c=='\\') state=3;
else if(c!='\'') state=7;
else return 0;
break;
case 3:
c=str[++i];
if(isteshu(c)) state=4;
else if(c=='x') state=5;
else if(c>='0'&&c<='7') state=6;
else return 0;
break;
case 4:
c=str[++i];
if(c=='\'') state=9;
else return 0;
case 5:
c=str[++i];
if((c>='a'&&c<='f')||(c>='A'&&c<='F')||(c>='0'&&c<='9'))
state=8;
else return 0;
break;
case 8:
c=str[++i];
if((c>='a'&&c<='f')||(c>='A'&&c<='F')||(c>='0'&&c<='9'))
state=8;
else if(c=='\'') state=9;
else return 0;
break;
case 6:
c=str[++i];
if(c>='0'&&c<='7') state=6;
else if(c=='\'') state=9;
else return 0;
break;
case 7:
c=str[++i];
if(c=='\'') state=9;
else return 0;
break;
case 9:
int k;
for( k=0;k<=i-start;k++)
{
token[j+k]=str[start+k];
}
j=j+k-1;
i++;
j++;
return 1;
break;
}
}
}
//int main()
//{
// char *str="'\111'";
// char token[20];
// int i=0;
// int j=0;
// int k=ischar(str,token,i,j);
// if(k==1)
// printf("%s\n",token);
// else
// printf("error");
// printf("%d%d",i,j);
//
//}
预处理程序(字符串中的空格不消除)
int formula_str(FILE *p) {
int i=0,j=0;
char str[N], str1[N],c;
while((c=fgetc(p))!=EOF) {
str[i] = c;
i++;
}
str[i] = '\0';
for(i=0; i<strlen(str); i++) {
if(str[i]=='/'&&str[i+1]=='/') {
while(str[i++]!='\n') {}
i--;
}//单行注释
else if(str[i]=='/'&&str[i+1]=='*') {
while(!(str[i]=='*'&&str[i+1]=='/')) {
i++;
}
i+=1;
}//多行注释
else if(str[i]==' '&&str[i+1]==' ') {
while(str[i]==' ') {
i++;
}
i--;
if(str1[j-1]!=' '&&j>0)
str1[j++]=' ';
}//多个空格,去除空格
else if(str[i]=='"')
{
str1[j++]=str[i++];
int starti=i,startj=j;
while(str[i]!='"'&&str[i]!='\0')
{
str1[j++]=str[i++];
}
if(str[i]=='"') {str1[j++]=str[i++];}
else {
i=starti;j=startj;
}
}
else if(str[i]=='\n'||str[i]=='\r'||str[i]=='\t') {
if(str1[j-1]!=' ')
str1[j++]=' ';
} else str1[j++] = str[i]; //其他字符处理
}
str1[j] = '\0';
if((p = fopen(".\\test1.txt","w"))==NULL) {
printf("创建文件失败");
return 0;
}
puts(str1);
fputs(str1,p);
fclose(p);
}
//int main() {
// FILE *p;
// char str[N],str1[N],c;
// if((p=fopen(".\\test.txt","r"))==NULL) {
// printf("打开文件失败");
// return 0;
// }
// formula_str(p);
// fclose(p);
// return 0;
//}