当前位置:编程学习 > C/C++ >>

词法分析器(C语言版)

词法分析器:
有限状态机的理论并不难,但是如果把状态机理论转换成代码,这个就需要思考了
 
数据结构设计:
[cpp] 
char charList[_CHARLIST_SIZE][15] = {0};  
char charList_nu[_CHARLIST_SIZE] = {0};  
char charList_index = 0;  
  
char numList[_NUMLIST_SIZE][15] = {0};  
char numList_nu[_CHARLIST_SIZE] = {0};  
char numList_index = 0;  
  
char delimilterList[_DELIMILTER_SIZE][15] = {0};  
char delimilterList_nu[_DELIMILTER_SIZE] = {0};  
char delimilterList_index = 0;  
 
 
由于最后输出需要看到非保留字和数字本身,以及出现的行号,所以这里用三个变量来记录,其中*_index 表示的数组的长度。
 
保留字:
[cpp]  
char reserveList[_RESERVE_NUM][15] = {  
    "void", "int", "char", "float", "double",  
    "while", "auto", "break", "case", "const",  
    "continue", "default", "do", "else", "enum",  
    "extern", "for", "goto", "if", "long",  
    "return", "short", "signed", "sizeof", "static",  
    "struct", "switch", "typedef", "union", "unsigned",  
    "volatile",  "redister"  
};  
 
 
Google后所查询到的保留字,这里我没有发现main,由此可见main 应该是预处理的时候给处理掉了。
状态机:
由于书上的内容不全,因此在编写的时候在判断 isLetter 加入了’_’,判断数字的时候加入了+- 号的判断,以及双引号的判断。
 
待编译内容
[cpp]  
void _fun() {  
  
}  
  
int main() {  
    int a = -111;  
    int b = +1;  
    printf("%d, a);  
    return 0;  
}  
 
 
可以看到这个代码是正确的代码。
运行后的结果,可以看到字符和常量已经分别出来了,这里我就不截图了,太麻烦。
 
在处理双引号的时候,当匹配到第一个引号时,即是状态机的初态,遇到下一个引号即到达终态,但是如果是错误代码(如下图),即无法到达终态,怎么办?
对于这种情况我没有单独处理,输出结果如下:
 
我们看到这里有一个总行数total nu 为7是错误的。因为我们在处理引号的初态时,始终无法匹配到第二个引号,自然也就始终把 /n 当成是引号中的内容,在以引号为初态的状态机中跳转。
关于回退指针,由于我没有一次读取到一个字符数组中,所以用了一个内置函数 ungetc,能将字符放回到流中
由于要以文本输出,就用freopen,然后fprintf即可,如果用fputc的话只能单个的输入。
 
对于数字的处理(下图为样例):
由此可见第一个是正确的输入,后两个均为不可识别的部分。下图为我识别出的部分
 
原本我想的是这样的识别肯定是错误的,因为它把不应该识别的部分也识别出来了,也就是说这里存在语法错误。但是后来一想,这是对的,因为只要存在不识别的部分,就直接报错。我们只需要关注需要识别的部分即可。这里可以很清楚的看到我把-3.12e+1.11识别出来了。
如果要让line 2和line 3不显示东西的话,需要考虑的问题就是当终态出现的时候,比如识别+1e-e时,先识别 +1e-,然后当识别e 的时候,这里出现了错误,无法到达终态。然后用ungetc回退,之后再次读入e,这里就当成了一个字符,即最后在line 2显示出了e ,这就是原因。Line3也是。但是如我之前所说,只要出现识别不了的东西,直接报错即可。我这里通过返回error,并且这个error是用lastRetval全局变量来标识的,这和windows编程里的getLastError有着一样的意思。
 
由于是现学现写,不免有部分是错误的。还望各位大神指点,而且目前对语法分析,和语义分析还不清楚。
 
代码:
 
[cpp] 
#include <stdio.h>  
#include <iostream>  
#include <cstring>  
  
#define NUMERROR -1  
  
#define _RESERVE_NUM 32  
#define _DELIMILTER_NUM 8  
#define _DELIMILTER_SIZE 100  
#define _CHARLIST_SIZE 100  
#define _NUMLIST_SIZE 100  
#define _TOKEN_SIZE 100  
#define COL 1000  
  
#define LT 1  
#define LE 2  
#define EQ 3  
  
using namespace std;  
  
FILE* fp;  
int lastRetval = 0;  
  
char charList[_CHARLIST_SIZE][15] = {0};  
char charList_nu[_CHARLIST_SIZE] = {0};  
char charList_index = 0;  
  
char numList[_NUMLIST_SIZE][15] = {0};  
char numList_nu[_CHARLIST_SIZE] = {0};  
char numList_index = 0;  
  
char delimilterList[_DELIMILTER_SIZE][15] = {0};  
char delimilterList_nu[_DELIMILTER_SIZE] = {0};  
char delimilterList_index = 0;  
  
char reserveList[_RESERVE_NUM][15] = {  
    "void", "int", "char", "float", "double",  
    "while", "auto", "break", "case", "const",  
    "continue", "default", "do", "else", "enum",  
    "extern", "for", "goto", "if", "long",  
    "return", "short", "signed", "sizeof", "static",  
    "struct", "switch", "typedef", "union", "unsigned",  
    "volatile",  "redister"  
};  
  
char delimilter[_DELIMILTER_NUM][5] = {  
    "+", "-", "*", "/", "<", ";", "<=", "=="      // six plus two  
};  
  
void nu_print(int nu) {  
    int i, cindex, nindex, flag, hasPrint;  
    cindex = nindex = 0;  
    printf("\n======================== each line to see =========================\n");  
    for(i = 0; i < nu; i++) {  
        hasPrint = 0;  
        for( ; cindex <= charList_index || nindex <= numList_index; ) {  
            flag = 0;  
            if(charList_nu[cindex] == i+1) {  
                if(0 == hasPrint) {  
补充:软件开发 , C++ ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,