编译原理课程实验一——词法分析

编译原理课程实验一——词法分析

实验目的

  1. 巩固对词法分析的基本功能和原理的认识。
  2. 能够应用自动机的知识进行词法分析。
  3. 理解并处理词法分析中的异常和错误。

实验要求

  1. 掌握词法分析的基本功能,并将其实现。
  2. 词法分析程序应具有较好的可扩展性,应清晰明确。
  3. 除对相关问题的全面考虑外,还需对局部作一些优化考虑(如符号表)

实验内容

  1. 给出语言的词法规则描述
  • 标识符、关键字、整常数、字符常数、浮点常数
  • 单界符:+,-,X,:,…
  • 双界符:/*,:=,…
  • 注释
  1. 针对这种单词的状态转换图和程序框图
  2. 核心数据结构的设计(如符号表、关键字等)
  3. 错误处理(错误的位置及类型等)

代码

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#define SIZE 10240 //默认大小

int token;            // 当前标记
char *src;         // 指向源代码字符串指针
int poolsize;         // 默认文本/数据大小
int line;        // 源码行号

char *keywords[26]={
    "main",   "if",       "then",   "while",  "do",     "static", "default",
    "do",     "int",      "double", "struct", "break",  "else",   "long",
    "switch", "case",     "typedf", "char",   "return", "const",  "float",
    "short",  "continue", "for",    "void",   "sizeof"
};

typedef struct node{
    int key;
    char value[100];
    struct node *next;
}node;

//用于词法分析,获取下一个标记,它将自动忽略空白字符。
struct node* next(struct node *p){
    int key = 0, i, j;
    char value[100];
    for(i = 0;i < 100; i++){
        value[i] = 0;
    }
    while(1){   //跳过不识别的字符以及处理空白字符
        token = *src;
        src++;
        if (token == '\n'){    //处理换行符,当前的行号加一
            ++line;
        }
        else if(token == ' '){
            if(*src == ' '){
                src++;
            }
        }
        else if (token == '#'){   //处理宏定义
            while (*src != 0 && *src != '\n'){
                src++;
            }
            key = 0;
            value[0] = '#';
            break;
        }
        else if ((token >= 'a' && token <= 'z') || (token >= 'A' && token <= 'Z') || (token == '_')){
            // 解析标识符
            i = 0;
            value[i]=token;
            while ((*src >= 'a' && *src <= 'z') || (*src >= 'A' && *src <= 'Z') || (*src >= '0' && *src <= '9') || (*src == '_')){
                value[i+1] = *src;
                src++;
                i++;
            }
            value[i+1] = '\0';
            key = 301;
            //查询已有的标识符
            for (j = 0; j < 26; j++){
                if (strcmp(value, keywords[j]) == 0){
                    key = j + 1;
                    break;
                }
            }
            break;
        }
        //整数 和 浮点数
        else if (token >= '0' && token <= '9'){
            value[0] = token;
            if (token > '0'){
                for (i = 1; *src >= '0' && *src <= '9'; i++){
                    value[i] = *src;
                    src++;
                }
                int temp = i;
                if (*src == '.'){
                    value[temp] = *src;
                    src++;
                    for (int j = temp + 1; *src >= '0' && *src <= '9'; j++){
                        value[j] = *src;
                        src++;
                    }
                    key = 402;
                    break;
                }else{
                    key = 401;
                    break;
                }
            }
            else{
                if (*src == '.'){
                    value[1] = *src;
                    src++;
                    for (i = 2; *src >= '0' && *src <= '9'; i++){
                        value[i] = *src;
                        src++;
                    }
                    key = 402;
                    break;
                }else{
                    key = 401;
                    break;
                }
            }
        }
        //字符串
        else if (token == 34){
            value[0] = (char)34;
            i = 1;
            while (*src != (char)34){
                value[i] = *src;
                i++;
                src++;
            }
            value[i] = (char)34;
            src++;
            key = 403;
            break;
        }
        //注释
        else if (token == '/'){
            if (*src == '/'){
                // skip comments
                value[0] = '/';
                value[1] = '/';
                i = 2;
                src++;
                while (*src != '\n'){
                    value[i] = *src;
                    i++;
                    src++;
                }
                key = 501;
                break;
            }
            else if (*src == '*'){
                value[0] = '/';
                value[1] = '*';
                i = 2;
                src++;
                while (*src != '\n'){
                    value[i] = *src;
                    i++;
                    src++;
                }
                key = 502;
                break;
            }
            else{
                // divide operator
                key = 101;
                value[0] = token;
                break;
            }
        }
        else if (token == '+'){
            // parse '+' and '++'
            if (*src == '+'){
                src++;
                key = 102;
                value[0] = value[1]='+';
                break;
            }
            else{
                key = 103;
                value[0] = '+';
                break;
            }
        }
        else if (token == '-'){
            // parse '-' and '--'
            if (*src == '-'){
                src++;
                key = 104;
                value[0] = value[1]='-';
                break;
            }
            else{
                key = 105;
                value[0] = '-';
                break;
            }
        }
        else if (token == '*'){
            key = 106;
            value[0] = '*';
            break;
        }
        else if (token == '='){
            // parse '==' and '='
            if (*src == '='){
                src++;
                key = 107;
                value[0] = value[1] = '=';
                break;
            }
            else{
                key = 108;
                value[0] = '=';
                break;
            }
        }
        else if (token == '!'){
            // parse '!='
            if (*src == '='){
                src++;
                key = 109;
                value[0] = '!';
                value[1] = '=';
                break;
            }
        }
        else if (token == '<'){
            // parse '<=', '<<' or '<'
            if (*src == '='){
                src++;
                key = 110;
                value[0] = '<';
                value[1] = '=';
                break;
            }
            else if (*src == '<'){
                src++;
                key = 111;
                value[0] = value[1]='<';
                break;
            }
            else{
                key = 112;
                value[0] = '<';
                break;
            }
        }
        else if (token == '>'){
            // parse '>=', '>>' or '>'
            if (*src == '='){
                src++;
                key = 113;
                value[0] = '>';
                value[1] = '=';
                break;
            }
            else if (*src == '>'){
                src++;
                key = 114;
                value[0] = value[1]='>';
                break;
            }
            else{
                key = 115;
                value[0] = '>';
                break;
            }
        }
        else if (token == '|'){
            // parse '|' or '||'
            if (*src == '|'){
                src++;
                key = 116;
                value[0] = value[1]='|';
                break;
            }
            else{
                key = 117;
                value[0] = '|';
                break;
            }
        }
        else if (token == '&'){
            // parse '&' and '&&'
            if (*src == '&'){
                src++;
                key = 118;
                value[0] = value[1]='&';
                break;
            }
            else{
                key = 119;
                value[0] = '&';
                break;
            }
        }
        else if (token == '^'){
            key = 120;
            value[0] = '^';
            break;
        }
        else if (token == '%'){
            key = 121;
            value[0] = '%';
            break;
        }
        else if (token == '['){
            key = 122;
            value[0] = '[';
            break;
        }
        else if (token == ']'){
            key = 123;
            value[0] = ']';
            break;
        }
        else if (token == ';'){
            key = 201;
            value[0] = ';';
            break;
        }
        else if (token == '{'){
            key = 251;
            value[0] = '{';
            break;
        }
        else if (token == '}'){
            key = 252;
            value[0] = '}';
            break;
        }
        else if (token == '('){
            key = 253;
            value[0] = '(';
            break;
        }
        else if (token == ')'){
            key = 254;
            value[0] = ')';
            break;
        }
        else if (token == ','){
            key = 202;
            value[0] = ',';
            break;
        }
        else if(token==0){
            break;
        }
        else {
            printf("Error,第%d行出现错误!\n", line);
            src++;
        }
    }
    p->key = key;
    for(i = 0;i < 100;i++){
        p->value[i] = value[i];
    }
    node *q = (node *)malloc(sizeof(node));
    q->next = NULL;
    p->next = q;
    return p;
}

//词法分析的入口,分析整个 C 语言程序。
void program(struct node *p){
    printf("词法分析产生的词法二元式为: \n");
    p=next(p);                  // 获取下一个标记
    while (token > 0){
        printf("< %d , %s >\n", p->key, p->value);
        p=p->next;
        next(p);
    }
}

//主函数
int main(void){
    int i;
    FILE *fd;
    char path[100];
    struct node *head;

    line = 1;
    
    head = (node *)malloc(sizeof(node));
    head->next = NULL;

    printf("词法分析器\n"
           "请输入源语言文件绝对路径: ");
    scanf("%s", path);

    if ((fd = fopen(path, "r")) == NULL){
        printf("could not open(%s)\n", path);
        return -1;
    }

    if (!(src = (char *)malloc(SIZE))){
        printf("could not malloc(%d) for source area\n", poolsize);
        return -1;
    }
    // 读取源文件
    if ((i = fread(src,1,SIZE,fd)) <= 0){
        printf("read() returned %d\n", i);
        return -1;
    }
    src[i] = 0; // 添加EOF字符
    fclose(fd);
    program(head);
    return 0;
}

符号表

在这里插入图片描述
在这里插入图片描述

测试程序

#include <stdio.h>
//get fibonacci : programmer
int fibonacci(int i) {
    if (i <= 1) {
        return 1;
    }
    else{
        return fibonacci(i-1) + fibonacci(i-2);
    }
}
/* main */
int main()
{
    int i;
    float f, ff;
    f = 0.123;
    ff = 12.30;
    i = 0;
    char temp[100] = "Hello";
    while (i <= 10) {
        //printf("fibonacci(%2d) = %d\n", i, fibonacci(i));
        fibonacci(i);
        ?
        i = i + 1;
    }
    return 0;
}

词法分析结果(部分)

在这里插入图片描述

结语

本博客做得十分匆忙,因此内容十分粗糙。并且本文的词法分析程序实现的方式比较low(逐个字符进行判断),没有用到自动机等内容(暂时没有这么多时间来实现)。算是先挖个坑吧,以后有时间了再认真重新更新一篇(然后大概率就忘了)。

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值