编译原理实验一:词法分析程序设计实验
编译原理实验一
结果(只是基础实验还没做拓展实验,我太喜欢这个风格的vscode了,多贴一次哈哈哈哈哈)
对实验指导书源程序进行一些补充和少量修改
程序一:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#define ID 7
#define INT 8
#define REAL 9
#define LT 10
#define LE 11
#define EQ 12
#define NE 13
#define GT 14
#define GE 15
#define IS 16
#define PL 17
#define MI 18
#define MU 19
#define DI 20
char TOKEN[20];
void report_error(char *s)
{
printf("Having Error: %s", *s);
}
void out(int x, char *s)
{
switch (x)
{
case 7:
{
printf("%s,%s\n", "ID", s);
break;
}
case 8:
{
printf("%s,%s\n", "INT", s);
break;
}
case 10:
{
printf("%s,%s\n", "LT", s);
break;
}
case 11:
{
printf("%s,%s\n", "LE", s);
break;
}
case 12:
{
printf("%s,%s\n", "EQ", s);
break;
}
case 13:
{
printf("%s,%s\n", "NE", s);
break;
}
case 14:
{
printf("%s,%s\n", "GT", s);
break;
}
case 15:
{
printf("%s,%s\n", "GE", s);
break;
}
case 16:
{
printf("%s,%s\n", "IS", s);
break;
}
case 17:
{
printf("%s,%s\n", "PL", s);
break;
}
case 18:
{
printf("%s,%s\n", "MI", s);
break;
}
case 19:
{
printf("%s,%s\n", "MU", s);
break;
}
case 20:
{
printf("%s,%s\n", "DI", s);
break;
}
default:
{
printf("%s,%s\n", KeyWordTable[x], s);
break;
}
}
}
/* 建立保留字表 */
#define MAX_KEY_NUMBER 20 /*关键字的数量*/
#define KEY_WORD_END "waiting for your expanding" /*关键字结束标记*/
char *KeyWordTable[MAX_KEY_NUMBER] = {"begin", "end", "if", "then", "else", "switch", "case", KEY_WORD_END};
/* 查保留字表,判断是否为关键字
不是关键字,返回0,是关键字,返回n+1, n为关键字数组中所找到的相同的关键字的索引位置*/
int lookup(char *token)
{
int n = 0;
while (strcmp(KeyWordTable[n], KEY_WORD_END)) /*如果比较到最后一位,也就是KEY_WORD_END,也就是已经确定都没有相同的,返回0*/
{
/*strcmp比较两串是否相同,若相同返回0*/
/*相等:strcmp函数返回0,加上!后为:TRUE 进入if内部执行语句;
不相等: strcmp返回其他正数或负数,这些返回值都等价于:TRUE ,加上!后,都为:FALSE 不进入if内部语句*/
if (!strcmp(KeyWordTable[n], token))
{
return n + 1; /*根据单词分类码表I,设置正确的关键字类别码,并返回此类别码的值*/
break;
}
n++;
}
return 0; /*单词不是关键字,而是标识符*/
}
void scanner_example(FILE *fp)
{
char ch;
int i = 0;
int c = 0;
ch = fgetc(fp); /*取出一个字符*/
/*首字符为字母,字母数字混杂*/
if (isalpha(ch)) /*是否是字母*/
{
TOKEN[0] = ch;
ch = fgetc(fp); /*取出下一个字符*/
i = 1;
while (isalnum(ch)) /*是否是字母或者数字*/
{
TOKEN[i] = ch;
i++;
ch = fgetc(fp); /*取出一个字符*/
}
/*跳出循环之后,fp指针指向的字符,不再是数字或者字母*/
TOKEN[i] = '\0';
fseek(fp, -1, 1); /*fp指针从当前位置往前挪一位*/
c = lookup(TOKEN); /*判断是否是关键字,不是的话返回0*/
if (c == 0)
out(ID, TOKEN);
else
out(c - 1, " "); /*因为lookup函数返回值为n+1*/
}
/*首字符是数字,整型数字*/
else if (isdigit(ch)) /*是否是数字*/
{
TOKEN[0] = ch;
ch = fgetc(fp); /*取出第二个字符*/
i = 1;
while (isdigit(ch)) /*后面取出的字符都依然是数字*/
{
TOKEN[i] = ch;
i++;
ch = fgetc(fp);
}
/*跳出循环之后,fp指针指向的字符,不再是数字*/
TOKEN[i] = '\0';
fseek(fp, -1, 1); /*fp指针从当前位置往前挪一位*/
out(INT, TOKEN);
}
else
{
switch (ch)
{
case '<':
{
ch = fgetc(fp);
if (ch == '=')
out(LE, " ");
else if (ch == '>')
out(NE, " ");
else
{ /*下一位不是=或者> :当做只有< */
fseek(fp, -1, 1); /*fp指针从当前位置往前挪一位*/
out(LT, " ");
}
break;
}
case '=':
{
out(EQ, " ");
break;
}
case '>':
{
ch = fgetc(fp);
if (ch == '=')
out(GE, " ");
else
{ /*下一位不是= :当做只有> */
fseek(fp, -1, 1); /*fp指针从当前位置往前挪一位*/
out(GT, " ");
}
break;
}
case ':':
{
ch = fgetc(fp);
if (ch == '=')
{
out(IS, " ");
}
else
{ /*冒号后面跟着的不是等号的话*/
report_error(":");
fseek(fp, -1, 1);
}
}
case '+':
{
out(PL, " ");
}
case '-':
{
out(MI, " ");
}
case '*':
{
out(MU, " ");
}
case '/':
{
out(DI, " ");
}
default:
{
report_error(&ch);
break;
}
}
}
return;
}
程序二
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include<stdlib.h>
#define DIGIT 1
#define POINT 2
#define OTHER 3
#define POWER 4
#define PLUS 5
#define MINUS 6
#define UCON 7
/*Suppose the class number of unsigned constant is 7
假设无符号常量的类数为7*/
#define ClassOther 200
#define EndState -1
int w, n, p, e, d;
int Class;
/*Used to indicate class of the word
用来表示单词的类别*/
int ICON;
float FCON;
static int CurrentState;
/*Used to present current state, the initial value:0
用于表示当前状态,初始值:0*/
int GetChar(void);
int EXCUTE(int, int);
int HandleOtherWord(void)
{
return ClassOther;
}
int HandleError(void)
{
printf("Error!\n");
return 0;
}
int GetChar(void)
{
int c;
c = getchar();
if (isdigit(c))
{
d = c -'0';
return DIGIT;
}
if (c =='.')
return POINT;
if (c =='E'|| c =='e')
return POWER;
if (c =='+')
return PLUS;
if (c =='-')
return MINUS;
return OTHER;
}
int EXCUTE(int state, int symbol)
{
switch (state)
{
case 0:
switch (symbol)
{
case DIGIT:
n = 0;
p = 0;
e = 1;
w = d;
CurrentState = 1;
Class = UCON;
break;
case POINT:
w = 0;
n = 0;
p = 0;
e = 1;
CurrentState = 3;
Class = UCON;
break;
default:
HandleOtherWord();
Class = ClassOther;
CurrentState = EndState;
}
break;
case 1:
switch (symbol)
{
case DIGIT:
w = w * 10 + d;
break; //CurrentState=1
case POINT:
CurrentState = 2;
break;
case POWER:
CurrentState = 4;
break;
default:
ICON = w;
CurrentState = EndState;
}
break;
case 2:
switch (symbol)
{
case DIGIT:
n++;
w = w * 10 + d;
break;
case POWER:
CurrentState = 4;
break;
default:
FCON = w * pow(10, e * p - n);
CurrentState = EndState;
}
break;
case 3:
switch (symbol)
{
case DIGIT:
n++;
w = w * 10 + d;
CurrentState = 2;
break;
default:
HandleError();
CurrentState = EndState;
}
break;
case 4:
switch (symbol)
{
case DIGIT:
p = p * 10 + d;
CurrentState = 6;
break;
case MINUS:
e = -1;
CurrentState = 5;
break;
case PLUS:
CurrentState = 5;
break;
default:
HandleError();
CurrentState = EndState;
}
break;
case 5:
switch (symbol)
{
case DIGIT:
p = p * 10 + d;
CurrentState = 6;
break;
default:
HandleError();
CurrentState = EndState;
}
break;
case 6:
switch (symbol)
{
case DIGIT:
p = p * 10 + d;
break;
default:
FCON = w * pow(10, e * p - n);
CurrentState = EndState;
}
break;
}
return CurrentState;
}
int LEX(void)
{
int ch;
CurrentState = 0;
while (CurrentState != EndState)
{
ch = GetChar();
EXCUTE(CurrentState, ch);
}
fseek(fp,-1,1);
//return Class;
printf("w: %d n: %d p: %d e: %d d: %d", w, n, p, e, d);
printf("\n ICON: %.3f, FCON: %.3f CLASS: %d", ICON, FCON, Class);
}
int main(){
LEX();
system("pause");
}
写实验二的时候找到的实验一的一个逻辑错误
一开始没有写这句回退fp指针,结果就是: “字符c实数字符a字符b”这样的字符串在判断的时候,会在识别出实数之后把fp指针向后多走一位,这样字符A就根本没有被识别的机会,这个事情是在实验二识别基础算术表达式的时候发现的
但是程序二是建立在手动输入上的,需要将程序一二做一个合体,读取同一个文件
所以最终程序 :
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#define ID 7
#define INT 8
#define REAL 9
#define LT 10
#define LE 11
#define EQ 12
#define NE 13
#define GT 14
#define GE 15
#define IS 16
#define PL 17
#define MI 18
#define MU 19
#define DI 20
/****************************判断实数**************************************/
#define DIGIT 1
#define POINT 2
#define OTHER 3
#define POWER 4
#define PLUS 5
#define MINUS 6
#define UCON 7
/*Suppose the class number of unsigned constant is 7
假设无符号常量的类数为7*/
#define ClassOther 200
#define EndState -1
int w, n, p, e, d;
int Class;
/*Used to indicate class of the word
用来表示单词的类别*/
int ICON;
float FCON;
static int CurrentState;
/*Used to present current state, the initial value:0
用于表示当前状态,初始值:0*/
int GetChar(void);
int EXCUTE(int, int);
int HandleOtherWord(void)
{
return ClassOther;
}
int HandleError(void)
{
printf("Error!\n");
return 0;
}
int GetChar(FILE *fp)
{
int c;
c = fgetc(fp);
if (isdigit(c))
{
d = c - '0';
return DIGIT;
}
if (c == '.')
return POINT;
if (c == 'E' || c == 'e')
return POWER;
if (c == '+')
return PLUS;
if (c == '-')
return MINUS;
return OTHER;
}
int EXCUTE(int state, int symbol)
{
switch (state)
{
case 0:
switch (symbol)
{
case DIGIT:
n = 0;
p = 0;
e = 1;
w = d;
CurrentState = 1;
Class = UCON;
break;
case POINT:
w = 0;
n = 0;
p = 0;
e = 1;
CurrentState = 3;
Class = UCON;
break;
default:
HandleOtherWord();
Class = ClassOther;
CurrentState = EndState;
}
break;
case 1:
switch (symbol)
{
case DIGIT:
w = w * 10 + d;
break; //CurrentState=1
case POINT:
CurrentState = 2;
break;
case POWER:
CurrentState = 4;
break;
default:
ICON = w;
CurrentState = EndState;
}
break;
case 2:
switch (symbol)
{
case DIGIT:
n++;
w = w * 10 + d;
break;
case POWER:
CurrentState = 4;
break;
default:
FCON = w * pow(10, e * p - n);
CurrentState = EndState;
}
break;
case 3:
switch (symbol)
{
case DIGIT:
n++;
w = w * 10 + d;
CurrentState = 2;
break;
default:
HandleError();
CurrentState = EndState;
}
break;
case 4:
switch (symbol)
{
case DIGIT:
p = p * 10 + d;
CurrentState = 6;
break;
case MINUS:
e = -1;
CurrentState = 5;
break;
case PLUS:
CurrentState = 5;
break;
default:
HandleError();
CurrentState = EndState;
}
break;
case 5:
switch (symbol)
{
case DIGIT:
p = p * 10 + d;
CurrentState = 6;
break;
default:
HandleError();
CurrentState = EndState;
}
break;
case 6:
switch (symbol)
{
case DIGIT:
p = p * 10 + d;
break;
default:
FCON = w * pow(10, e * p - n);
CurrentState = EndState;
}
break;
}
return CurrentState;
}
int LEX(FILE *fp)
{
int ch;
CurrentState = 0;
while (CurrentState != EndState)
{
ch = GetChar(fp);
EXCUTE(CurrentState, ch);
}
fseek(fp,-1,1);
/*printf("\nw: %d n: %d p: %d e: %d d: %d", w, n, p, e, d);*/
/*printf("\n ICON: %.3f, FCON: %.3f CLASS: %d\n\n", ICON, FCON, Class);*/
printf("REAL, %.3f\n", FCON);
}
/***********************************判断实数***********************************/
/************************************判断是否是保留字********************************/
/* 建立保留字表 */
#define MAX_KEY_NUMBER 20 /*关键字的数量*/
#define KEY_WORD_END "waiting for your expanding" /*关键字结束标记*/
char *KeyWordTable[MAX_KEY_NUMBER] = {"begin", "end", "if", "then", "else", "switch", "case", KEY_WORD_END};
/* 查保留字表,判断是否为关键字
不是关键字,返回0,是关键字,返回n+1, n为关键字数组中所找到的相同的关键字的索引位置*/
int lookup(char *token)
{
int n = 0;
while (strcmp(KeyWordTable[n], KEY_WORD_END)) /*如果比较到最后一位,也就是KEY_WORD_END,也就是已经确定都没有相同的,返回0*/
{
/*strcmp比较两串是否相同,若相同返回0*/
/*相等:strcmp函数返回0,加上!后为:TRUE 进入if内部执行语句;
不相等: strcmp返回其他正数或负数,这些返回值都等价于:TRUE ,加上!后,都为:FALSE 不进入if内部语句*/
if (!strcmp(KeyWordTable[n], token))
{
return n + 1; /*根据单词分类码表I,设置正确的关键字类别码,并返回此类别码的值*/
break;
}
n++;
}
return 0; /*单词不是关键字,而是标识符*/
}
/************************************判断是否是保留字***************************************/
/**********************************非实数的所有显示与报错*********************************************/
void report_error(char *s)
{
printf("Having Error:%s\n",s);
}
void out(int x, char *s)
{
switch (x)
{
case 7:
{
printf("%s,%s\n", "ID", s);
break;
}
case 8:
{
printf("%s,%s\n", "INT", s);
break;
}
case 10:
{
printf("%s,%s\n", "LT", s);
break;
}
case 11:
{
printf("%s,%s\n", "LE", s);
break;
}
case 12:
{
printf("%s,%s\n", "EQ", s);
break;
}
case 13:
{
printf("%s,%s\n", "NE", s);
break;
}
case 14:
{
printf("%s,%s\n", "GT", s);
break;
}
case 15:
{
printf("%s,%s\n", "GE", s);
break;
}
case 16:
{
printf("%s,%s\n", "IS", s);
break;
}
case 17:
{
printf("%s,%s\n", "PL", s);
break;
}
case 18:
{
printf("%s,%s\n", "MI", s);
break;
}
case 19:
{
printf("%s,%s\n", "MU", s);
break;
}
case 20:
{
printf("%s,%s\n", "DI", s);
break;
}
default:
{
printf("%s,%s\n", KeyWordTable[x], s);
break;
}
}
}
/**********************************非实数的所有显示与报错*********************************************/
/**********************************扫描一次*********************************************/
void scanner_example(FILE *fp)
{
char TOKEN[20] = {};
char ch;
int i = 0;
int c = 0;
ch = fgetc(fp); /*取出一个字符*/
/*首字符为字母,字母数字混杂*/
if (isalpha(ch)) /*是否是字母*/
{
TOKEN[0] = ch;
ch = fgetc(fp); /*取出下一个字符*/
i = 1;
while (isalnum(ch)) /*是否是字母或者数字*/
{
TOKEN[i] = ch;
i++;
ch = fgetc(fp); /*取出一个字符*/
}
/*跳出循环之后,fp指针指向的字符,不再是数字或者字母*/
fseek(fp, -1, 1); /*fp指针从当前位置往前挪一位*/
c = lookup(TOKEN); /*判断是否是关键字,不是的话返回0*/
if (c == 0)
out(ID, TOKEN);
else
out(c - 1, " "); /*因为lookup函数返回值为n+1*/
}
/*首字符是数字,整型数字*/
else if (isdigit(ch)) /*是否是数字*/
{
TOKEN[0] = ch;
ch = fgetc(fp); /*取出第二个字符*/
i = 1;
while (isdigit(ch)) /*后面取出的字符都依然是数字*/
{
TOKEN[i] = ch;
i++;
ch = fgetc(fp);
}
/*跳出循环之后,fp指针指向的字符,不再是数字*/
if (ch != 'E' && ch != 'e' && ch != '.')
{
fseek(fp, -1, 1); /*fp指针从当前位置往前挪一位*/
out(INT, TOKEN);
}
else /*考虑实型常数*/
{
fseek(fp, -(i + 1), 1);
LEX(fp);
}
}
else
{
switch (ch)
{
case '<':
{
ch = fgetc(fp);
if (ch == '=')
out(LE, " ");
else if (ch == '>')
out(NE, " ");
else
{ /*下一位不是=或者> :当做只有< */
fseek(fp, -1, 1); /*fp指针从当前位置往前挪一位*/
out(LT, " ");
}
break;
}
case '=':
{
out(EQ, " ");
break;
}
case '>':
{
ch = fgetc(fp);
if (ch == '=')
out(GE, " ");
else
{ /*下一位不是= :当做只有> */
fseek(fp, -1, 1); /*fp指针从当前位置往前挪一位*/
out(GT, " ");
}
break;
}
case ':':
{
ch = fgetc(fp);
if (ch == '=')
{
out(IS, " ");
}
else
{ /*冒号后面跟着的不是等号的话*/
report_error(":");
fseek(fp, -1, 1);
}
break;
}
case '+':
{
out(PL, " ");
break;
}
case '-':
{
out(MI, " ");
break;
}
case '*':
{
out(MU, " ");
break;
}
case '/':
{
out(DI, " ");
break;
}
case ' ':
{
break;
}
case '\n':
{
break;
}
default:
{
report_error(&ch);
break;
}
}
}
return;
}
/**********************************扫描一次*********************************************/
int main()
{
FILE *fp = NULL;
fp = fopen("Test.txt", "r");
char ch;
while (1)
{
ch = fgetc(fp);
if (ch != EOF)
{
fseek(fp, -1, 1);
}
else
{
break;
}
scanner_example(fp);
}
fclose(fp);
system("pause");
}
分类:
编译原理
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具