📄 bianyi .txt
字号:
i++;
ch=fgetc(fp);
}
TOKEN[i]='\0';
fseek(fp,-1,1);
out(INT,TOKEN);
}
else
switch(ch)
{
case '<': ch=fgetc(fp);
if(ch=='=')
out(LE," ");
else if(ch=='>')
out(NE," ");
else
{
fseek(fp,-1,1);
out(LT," ");
}
break;
case '=': out(EQ, " "); break;
case '>': ch=fgetc(fp);
if(ch=='=')
out(GE," ");
else
{
fseek(fp,-1,1);
out(GT," ");
}
break;
case ':': ch=fgetc(fp);
if(ch=='=') // := 为赋值语句
out(FZ," ");
else
{
fseek(fp,-1,1);
report_error(ch);
}
break;
case '/': ch=fgetc(fp); //删除程序中的注释
if(ch=='/')
{
do
{
ch=fgetc(fp);
}while(ch!='\n');
graphnum++;
}
else
{
fseek(fp,-1,1);
out(DEV," ");
}
break;
case ' ' : break; //删除程序中的空格
case '\n': graphnum++; break; //删除程序中的回车,并记录程序编译到第几行
case ' ': break; //删除程序中的横向制表符
case -1 : break; //删除文件尾符号
default : report_error(ch);
break;
}
}
return;
}
void main(int argc,char *argv[])
{
FILE *fp;
try
{
if(argc!=2)
throw argc;
fp=fopen(argv[1],"r");
if(!fp)
throw argv[1];
}
catch(char *str)
{
cout<<"打开文件 : "<<str<<" 时发生错误!"<<endl;
exit(1);
}
catch(int)
{
cout<<"请输入一个文件名!"<<endl;
exit(1);
}
scanner_example(fp);
fclose (fp);
}
----------------------------------
一个词法分析示意程序
这里以开始定义的PASCAL语言子集的源程序作为词法分析程序的输入数据。在词法分析中,自文件头开始扫描源程序字符,一旦发现符合"单词"定义的源程序字符串时,将它翻译成固定长度的单词内部表示,并查填适当的信息表。经过词法分析后,源程序字符串(源程序的外部表示)被翻译成具有等长信息的单词串(源程序的内部表示),并产生两个表格:常数表和标识符表,它们分别包含了源程序中的所有常数和所有标识符。
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#define NULL 0
char *key[8]={"DO","BEGIN","ELSE","END","IF","THEN","VAR","WHILE"};/*用于指向关键字表*/
char *border[6]={",",";",":=",".","(",")"}; /*用于指向符号表*/
char *arithmetic[4]={"+","-","*","/"}; /*,指向算术运算符表*/
char *relation[6]={"<","<=","=",">",">=","<>"}; /*指向关系运算符表*/
char *consts[20]; /*指向常数表*/
char *label[20]; /*指向标识符表*/
FILE *fp; /*指向要分析的PASCAL源程序*/
int constnum=0,labelnum=0; /*存放当前常数个数和标识符个数*/
char alphaprocess(char buffer); /*关键字和标识符处理子函数*/
char digitprocess(char buffer); /*数字处理函数*/
char otherprocess(char buffer); /*其他字符处理函数*/
int search(char searchcar[],int wordtype); /*查找子函数*/
/**********************************************************
* 主函数打开要分析的PASCAL源文件,若不能正确打开,则报错。
* 先从源程序中读入一个字符ch,然后进行如下处理:
* ⒈ch是字符:转入关键字和标识符处理子函数;
* ⒉ch是数字:转入数字处理函数;
* ⒊ch是其他字符:转入其他字符处理子函数;
**********************************************************/
int main()
{
int i;
char cbuffer;
for (i=0;i<=20;i++)
{
label[i]=NULL;
consts[i]=NULL;
};
if (NULL==(fp=fopen("DEMO.PAS","r")))
printf("error");
else
{
cbuffer = fgetc(fp);
while (cbuffer!=EOF)
{
if (isalpha(cbuffer))
cbuffer=alphaprocess(cbuffer);
else if (isdigit(cbuffer))
cbuffer=digitprocess(cbuffer);
else if ((cbuffer==' ')||(cbuffer=='\n')||(cbuffer=='\t'))
cbuffer=fgetc(fp);
else cbuffer=otherprocess(cbuffer);
};
printf("Done\n");
};
return 0;
}
int search(char searchchar[],int wordtype)
{
int i=0;
switch (wordtype)
{
case 1:for (i=0;i<=7;i++)
{
if (strcmp(key[i],searchchar)==0)
return(i+1);
};
case 2:{for (i=0;i<=5;i++)
{
if (strcmp(border[i],searchchar)==0)
return(i+1);
};
return(0);
}
case 3:{for (i=0;i<=3;i++)
{
if (strcmp(arithmetic[i],searchchar)==0)
{
return(i+1);
};
};
return(0);
};
case 4:{for (i=0;i<=5;i++)
{
if (strcmp(relation[i],searchchar)==0)
{
return(i+1);
};
};
return(0);
};
case 5:{for (i=0;i<=constnum;i++)
{
if (strcmp(consts[i],searchchar)==0)
{
return(i+1);
};
}
consts[i-1]=(char *)malloc(sizeof(searchchar));
strcpy(consts[i-1],searchchar);
constnum++;
return(i);
};
case 6:{for (i=0;i<=labelnum;i++)
{
if (strcmp(label[i],searchchar)==0)
{
return(i+1);
};
}
label[i-1]=(char *)malloc(sizeof(searchchar));
strcpy(label[i-1],searchchar);
labelnum++;
return(i);
};
}
}
/**********************************************************
* ⒈将buffer送入临时数组alphatp[0],再读入一个字符至buffer;
* ⒉判断buffer是否为字符或数字,若是,则alphatp[1]=buffer;
* ⒊重复1,2,直到2判断为假;在alphatp末尾添加'\0';
* ⒋调用search()子函数,在关键字表中匹配alphatp,若匹配成功,则返回序号;
* ⒌否则调用search(),在标识符表中匹配alphatp,若匹配成功,则返回序号;
* ⒍在标识符表中添加alphatp,并返回序号;
***********************************************************/
char alphaprocess(char buffer)
{
int atype;
int i=-1;
char alphatp[20];
while ((isalpha(buffer))||(isdigit(buffer)))
{
alphatp[++i]=buffer;
buffer=fgetc(fp);
};
alphatp[i+1]='\0';
if (atype=search(alphatp,1))
printf("%s (1,%d)\n",alphatp,atype-1);
else
{
atype=search(alphatp,6);
printf("%s (6,%d)\n",alphatp,atype-1);
};
return(buffer);
}
char digitprocess(char buffer)
{
int i=-1;
char digittp[20];
int dtype;
while ((isdigit(buffer)))
{
digittp[++i]=buffer;
buffer=fgetc(fp);
}
digittp[i+1]='\0';
dtype=search(digittp,5);
printf("%s (5,%d)\n",digittp,dtype-1);
return(buffer);
}
char otherprocess(char buffer)
{
int i=-1;
char othertp[20];
int otype,otypetp;
othertp[0]=buffer;
othertp[1]='\0';
if (otype=search(othertp,3))
{
printf("%s (3,%d)\n",othertp,otype-1);
buffer=fgetc(fp);
return(buffer);
};
if (otype=search(othertp,4))
{
buffer=fgetc(fp);
othertp[1]=buffer;
othertp[2]='\0';
if (otypetp=search(othertp,4))
{
printf("%s (4,%d)\n",othertp,otypetp-1);
return(buffer);
}
else
othertp[1]='\0';
printf("%s (4,%d)\n",othertp,otype-1);
return(buffer);
};
if (buffer==':')
{
buffer=fgetc(fp);
if (buffer=='=')
printf(":= (2,2)\n");
buffer=fgetc(fp);
return(buffer);
}
else
{
if (otype=search(othertp,2))
{
printf("%s (2,%d)\n",othertp,otype-1);
buffer=fgetc(fp);
return(buffer);
}
};
printf("%c error,not a word\n",buffer);
buffer=fgetc(fp);
return(buffer);
}
-----------------------
前些天写了个小语言的词法分析程序,因为前些天在VC知识库看到一个pascal词法分析的程序,觉得写得挺复杂的。其实词法分析程序的原理都是一样的,所以我想只要搞明白了简单的词法分析程序,再写复杂的就不难了,无非是多加几个关键字,多写几个条件判断语句而已。词法分析是编译程序的基础,也是最简单的。好,现在让我们看程序吧。
先让我们看看这个小语言的文法吧。
G[<程序>]:
<程序>∷=<程序首部>;<分程序>.
<程序首部>∷=program<标识符>
<分程序>∷=<复合语句>
<复合语句>∷=begin<语句序列>end
<语句序列>∷=<语句>{;<语句>}
<语句>∷=<赋值语句>|<复合语句>|<条件语句>
<赋值语句>∷=<标识符>:=<表达式>
<条件语句>∷=if <布尔表达式> then <语句> else <语句>
<表达式>∷=<项>{(+|-)<项>}
<项>∷=<因式>{(*|/)<因式>}
<因式>∷=<标识符>|<无正负号常量>|’(’<表达式>’)’
<布尔表达式>∷=<表达式><关系运算符><表达式>
<关系运算符>∷= =|<|<=|>|>=|<>
<标识符>∷=<字母>{<字母>|<数字>}
<无正负号常量>∷=<数字>{<数字>}[.<数字>{<数字>}]
<字母>∷=a|b|c|d|e|f|g|……|u|v|w|x|y|z
<数字>∷=0|1|2|3|4|5|6|7|8|9
根据此文法,构造一词法分析程序。输入以“#”为结束符
按照这个文法,找出该语言的关键字,如program,begin,end ,if,then,else,以及其他一些特殊符号,然后再构造一个分析表,如下表:
单词符号 类别编号
标识符 1
常数 2
if 3
then 4
else 5
program 6
begin 7
end 8
+ 9
- 10
* 11
/ 12
( 13
) 14
> 15
>= 16
< 17
<= 18
<> 19
:= 20
; 21
. 22
, 23
根据这个表来构造程序,程序的核心是下面的这个函数,
/*******************************************************************
以下为主分析函数
从输入文件里面读,把分析结果写到输出文件中
参数:fpin :输入文件指针 fpout: 输出文件指针
*******************************************************************/
void parse(FILE* fpin,FILE* fpout)
{
char arr[MAXBUF];//读出的最长的字符串不超过MAXBUF,MAXBUF定义为255
//够长了我想
int i=0;//分析含字母的字符串用
int j=0;//分析纯数字的字符串用
while(1)
{
fscanf(fpin,"%c",&ch);//从输入文件中读入一个字符
if( ch=='' ''|| ch ==''\t'')//过滤掉空格和tab
;
else if( ch==''\n'')//回车换行符,为下面进行错误判断
lineno++;
else if( IsDigit(ch))//读入的是数字
{
while(IsDigit(ch))
{
arr[j] = ch;
j++;
fscanf(fpin,"%c",&ch);
}
fseek(fpin,-1L,SEEK_CUR);//文件指针后退一个字节
char* temp1 =(char*)malloc(j+1);/
memcpy(temp1,arr,j);
temp1[j] =''\0'';//把数组里面的内容拷贝到连外一个数组里面,因为我定义的
//arr为255个字节,实际上写不到那么多,
//所以只拷贝实际上有数据的
j=0;//恢复初始状态,以备下次使用
fprintf(fpout,"%s\t\t%d\n",temp1,2);//常数
free(temp1);//释放内存
}
else if(IsAlpha(ch))//是字母开头的
{
while(IsAlpha(ch) || IsDigit(ch))
{
arr[i] =ch;
i++;
fscanf(fpin,"%c",&ch);
}
fseek(fpin,-1L,SEEK_CUR);
char* temp = (char*)malloc(i+1) ;
memcpy(temp,arr,i);
temp[i] =''\0'';
i=0;
/*基本思想同处理数字的*/
if(FindOK(temp))//FindOK函数在关键字表中查找和temp字符串相同的,
//找到就返回类别编号
{
fprintf(fpout,"%s\t\t%d \n",temp,FindOK(temp));
}
else
{
fprintf(fpout,"%s\t\t%d\n",temp,1);//标示符号
}
free(temp);
}
//以下为2字节的运算符号
else if( ch=='':'')//符号“:=”
{
fscanf(fpin,"%c",&ch);
if(ch==''='')
fprintf(fpout,"%s\t\t%d\n",":=",20);
else
fprintf(fpout,"error in compileing %d lines unknown character %c \n",lineno,ch);//出错了
}
else if(ch==''>'')//符号 “> “ 和”>=”
{
fscanf(fpin,"%c",&ch);
if(ch==''='')
fprintf(fpout,"%s\t\t%d\n",">=",16);
ellse
fprintf(fpout,">\t\t15\n");
}
else if( ch==''<'') //符号 “< “ 和”<=”
{
fscanf(fpin,"%c",&ch);
if(ch==''='')
{fprintf(fpout,"<=\t\t18\n");}
else if( ch==''>'')
{fprintf(fpout,"<>\t\t19");}
else
{fprintf(fpout,"<\t\t19\n");}
}
else {
//以下为一个字节的运算符号
if(ch==''-'') {fprintf(fpout,"%s\t\t%d\n",''-'',10);continue;}//在文件中输出为“- 10”
if(ch=='';'') {fprintf(fpout,";\t\t21\n");continue;}
if(ch==''+'') {fprintf(fpout,"+\t\t9\n");continue;}
if(ch==''*'') {fprintf(fpout,"*\t\t11\n");continue;}
if(ch==''/'') {fprintf(fpout,"/ \t\t12\n");continue;}
if(ch==''('') {fprintf(fpout,"(\t\t13\n");continue;}
if(ch=='')'') {fprintf(fpout,")\t\t14\n");continue;}
if(ch==''.'') {fprintf(fpout,".\t\t22\n");continue;}
if(ch=='','') {fprintf(fpout,",\t\t23\n");continue;}
if(ch==''#'') break;//分析结束
else fprintf(fpout,"error in compileing %d lines unknown character %c \n",lineno,ch);//出错了,输出出错信息
}
}
}
其他请看源代码,注释很详细,但是肯定有不足的地方,请大家吝赐教。有什么问题,可以给我发邮件。这是我第一次向VC知识库投稿,以后将会陆续写一些VC方面的程序来和大家共享。我的email:brilliant_zhang@21cn.com,QQ:110902663, 谢谢大家。
------------------------
词法分析是编译程序的第一步,是以后编译步骤:语法分析,语义分析以及代码生成的基础.目前可以利用LEX进行词法分析程序的编写,如果所要翻译的语言比较庞大则应该使用LEX,这就需要学习LEX的使用了,本文不使用该工具,而自己手工编写一个,旨在解除大家对编译系统的神秘感,也希望能给大家一个提示吧.网上有些词法分析程序的原代码,觉得写的挺复杂的。其实词法分析程序的原理都是一样的,所以我想只要搞明白了简单的词法分析程序,再写复杂的就不难了,无非是多加几个关键字,多写几个条件判断语句而已。词法分析是编译程序的基础,也是最简单的。好,现在让我们开始吧。
先让我们看看这个小语言的文法吧。
G[<程序>]:
<程序>∷=<程序首部>;<分程序>.
<程序首部>∷=program<标识符>
<分程序>∷=<复合语句>
<复合语句>∷=begin<语句序列>end
<语句序列>∷=<语句>{;<语句>}
<语句>∷=<赋值语句>|<复合语句>|<条件语句>
<赋值语句>∷=<标识符>:=<表达式>
<条件语句>∷=if <布尔表达式> then <语句> else <语句>
<表达式>∷=<项>{(+|-)<项>}
<项>∷=<因式>{(*|/)<因式>}
<因式>∷=<标识符>|<无正负号常量>|’(’<表达式>’)’
<布尔表达式>∷=<表达式><关系运算符><表达式>
<关系运算符>∷= =|<|<=|>|>=|<>
<标识符>∷=<字母>{<字母>|<数字>}
<无正负号常量>∷=<数字>{<数字>}[.<数字>{<数字>}]
<字母>∷=a|b|c|d|e|f|g|……|u|v|w|x|y|z
<数字>∷=0|1|2|3|4|5|6|7|8|9
根据此文法,构造一词法分析程序。输入以“#”为结束符
按照这个文法,找出该语言的关键字,如program,begin,end ,if,then,else,以及其他一些特殊符号,然后再构造一个分析表,如下表:
单词符号
类别编号
单词符号
类别编号
标识符
1
)
14
常数
2
>
15
if
3
>=
16
then
4
<
17
else
5
<=
18
program
6
<>
19
评论(条) 关闭页面 打印
---------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -