C语言实现简单的词法分析器(eclipse)

C语言实现简单的词法分析器

词法分析

词法分析是编译的第一个阶段,其任务是:从左至右对原程序进行扫描,产生一个个单词符号。

C语言子集的单词符号表

对常用有限个单词进行编码

(1)identify_char:标识符
(2)include等:关键词
(3)+ - * /:操作符
(4){ }等:分界符
(5)# 等:程序不能识别的字符
注:本段程序只能分析出下表给出的字符
单词符号表

词法分析的状态转换图如下

词法分析的状态转换图

根据词法分析器的状态装换图可以设计词法分析程序的框架:

(1)判断是否为关键字,字母,数字。

bool isKey(char * token);//keyword
bool isLetter(char letter);//letter
bool isDigit(char digit);//digit

(2)通过代码访问文件,文件指针依次扫描文件中的字符,如果文件指针遇到(\t,\n,’ '),程序什么都不做,将得到的字符串进行判断,文件指针向后退一格,准备读下一个字符串。
(3)对使用到的文件函数进行说明

//1.
/*从文件指针fgetc(stream)指向的文件读取一个字符,读取一个字节后,光标位置后移一个字节
 * format: int fgetc(FILE*stream)
 * 函数返回得到的字符值
 * 读到结尾或者读到错误,返回EOF
 * EOF是一个有效的整型值
 * 二进制文件使用feof函数进行结束检测
 * 用ferror函数进行出错检查
 //2.
 * /*int fseek(FILE*stream,long offset,int fromwhere),调整文件当前指针
 * 若果函数成功执行,stream指针将指向以fromwhere为基准,偏移offset个字节的位置,函数返回0
 * 若果函数执行失败(offset的值大于等于2*1024*1024*1024,即long的整数范围为2G),函数返回非零值
 * 偏移起始位置:文件头0(SEEK_SET)
 * 当前位置:当前位置1(SEEK_CUR)
 * 文件尾2(SEEK_END)*/
*/

(4)详细注释在代码在代码注释中。

测试文件:

分析文件

词法分析程序源代码

编译环境:eclipse + MinGW

#include<stdio.h>
#include<string.h>
#define bool int
#define true 1
#define false 0
#define MAX 11
char ch = ' ';
char* keyWord[11] = {"include","main","void","break","int","float","if","else","while","printf","for"};
char token[20];//定义获取的字符
//判断是否是关键字
bool isKey(char * token)
{
    for(int i = 0;i < MAX;i++)
    {
        if(strcmp(token,keyWord[i]) == 0)
            return true;
    }
    return false;
}
//判断是否是字母
bool isLetter(char letter)
{
    if((letter >= 'a' && letter <= 'z')||(letter >= 'A' && letter <= 'Z'))
        return true;
    else
        return false;
}
//判断是否是数字
bool isDigit(char digit)
{
    if(digit >= '0' && digit <= '9')
        return true;
    else
        return false;
}
//1.
/*从文件指针fgetc(stream)指向的文件读取一个字符,读取一个字节后,光标位置后移一个字节
 * format: int fgetc(FILE*stream)
 * 函数返回得到的字符值
 * 读到结尾或者读到错误,返回EOF
 * EOF是一个有效的整型值
 * 二进制文件使用feof函数进行结束检测
 * 用ferror函数进行出错检查
*/
void analyze(FILE *fpin)
{

    while((ch = fgetc(fpin)) != EOF){
        if(ch == ' '||ch == '\t'||ch == '\n'){}//读到空字符,空格,换行符什么都不做
        else if(isLetter(ch)){
            char token[20]={'\0'};
            int i=0;
            while(isLetter(ch)||isDigit(ch)){
                token[i] = ch;
                i++;
                ch = fgetc(fpin);//读下一个字符
            }
            //回退一个指针
            /*int fseek(FILE*stream,long offset,int fromwhere),调整文件当前指针
             * 若果函数成功执行,stream指针将指向以fromwhere为基准,偏移offset个字节的位置,函数返回0
             * 若果函数执行失败(offset的值大于等于2*1024*1024*1024,即long的整数范围为2G),函数返回非零值*
             * 偏移起始位置:文件头0(SEEK_SET)
             * 当前位置:当前位置1(SEEK_CUR)
             * 文件尾2(SEEK_END)*/
            fseek(fpin,-1L,SEEK_CUR);//文件指针停留在空字符,空格,换行符的位置上
            if(isKey(token)){
                //关键字
            	int i,j;
            	 for( i = 0;i < MAX;i++)
            	    {
            	        if(strcmp(token,keyWord[i]) == 0)j=i;
                } printf("%s\t%d\tkeyword\n",token,j);
            }
            else{
                //标识符
                printf("%s\t4\tidentify_char\n",token);
            }
        }
        else if(isDigit(ch)||(ch == '.'))
        {
            int i=0;
            char token[20]={'\0'};//清空缓冲数组;但文件指针还在;即读入下一个字符
            while(isDigit(ch)||(ch == '.'&&isDigit(fgetc(fpin))))
            {
                if(ch == '.')fseek(fpin,-1L,SEEK_CUR);
                token[i] = ch;
                i++;
                ch = fgetc(fpin);
            }
            fseek(fpin,-1L,SEEK_CUR);
            //属于无符号常数
            printf("%s\t11\tconstant\n",token);
            fflush(stdout);
        }
        else switch(ch){
            //运算符
            case '+':{
                        ch = fgetc(fpin);
                        if(ch == '+')
                        	{
                        	printf("++\t12\toperator\n");
                        	fflush(stdout);

                        	}
                        else {

                            printf("+ \t13\toperator\n");
                            fflush(stdout);
                            fseek(fpin,-1L,SEEK_CUR);
                        }
                     }break;
            case '-':{
                        ch = fgetc(fpin);
                        if(ch == '-')
                        	{
                        	printf("--\t14\toperator\n");
                        	fflush(stdout);

                        	}
                        else {

                        	printf("- \t15\toperator\n");
                        	fflush(stdout);
                            fseek(fpin,-1L,SEEK_CUR);
                        }
                     }break;
            case '*':printf("%c\t16\toperateor\n",ch);break;
            case '/':printf("%c\t17\toperateor\n",ch);break;
            //分界符
            case '(':printf("%c\t18\tboundary\n",ch);break;
            case ')':printf("%c\t19\tboundary\n",ch);break;
            case '[':printf("%c\t20\tboundary\n",ch);break;
            case ']':printf("%c\t21\tboundary\n",ch);break;
            case ';':printf("%c\t22\tboundary\n",ch);break;
            case '{':printf("%c\t23\tboundary\n",ch);break;
            case '}':printf("%c\t24\tboundary\n",ch);break;
            case '#':printf("%c\t25\tboundary\n",ch);break;
            //运算符
            case '=':{
                        ch = fgetc(fpin);
                        if(ch == '=')printf("==\t26\toperator\n");
                        else {
                        	printf("= \t27\toperator\n");
                            fseek(fpin,-1L,SEEK_CUR);
                        }
                     }break;
            case ':':{
                        ch = fgetc(fpin);
                        if(ch == '=')printf(":=\t28\toperator\n");
                        else {
                        	printf(": \t29\toperator\n");;
                            fseek(fpin,-1L,SEEK_CUR);
                        }
                     }break;
            case '>':{
                        ch = fgetc(fpin);
                        if(ch == '=')printf(">=\t30\toperator\n");
                        else {
                        	printf("> \t31\toperator\n");;
                            fseek(fpin,-1L,SEEK_CUR);
                        }
                     }break;
            case '<':{
                        ch = fgetc(fpin);
                        if(ch == '=')printf("<=\t32\toperator\n");
                        else {
                        	printf("< \t33\toperator\n");
                            fseek(fpin,-1L,SEEK_CUR);
                        }
                     }break;
            //无识别
            default: printf("%c\t34\tno_recognition\n",ch);
        }
    }
}
int main(){
    char input[30];
    FILE *fpin;
    printf("Please input the path of file that you want to compile:(C:\...)\n ");
    fflush(stdout);
    scanf("%s",input);
    if((fpin = fopen(input,"r")) != NULL)
        {
        	printf("File open success!\n");
        }
    else
        {
            printf("Path Error!\n\n");
            fflush(stdout);
        }
    printf("****************Lexical analysis start*********************\n");
    analyze(fpin);
    printf("****************Lexical analysis finish********************\n");
    fclose(fpin);
    printf("File close success!");
    return 0;
}
调试结果:

结果1
结果2
参考资料:
[1]:https://www.cnblogs.com/ya-qiang/p/8987926.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值