头歌编译原理实验1《 第1关:词法分析程序设计与实现》

AC CODE

c++ 复制代码
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
char prog[1000], token[20];
char ch;
int syn, p, m = 0, n, row = 1, sum = 0;
// 扩充关键字表
const char* rwtab[10] = { "if","int","for","while","do","return","break","continue", "using", "namespace" };
const char* rwtab1[8] = { "main","a","b","c","d","e","f","g" };

void scaner()
{
    // 初始化token数组
    for (n = 0; n < 20; n++) token[n] = '\0';
    // 跳过空白字符
    while (p < strlen(prog) && (prog[p] == ' ' || prog[p] == '\t' || prog[p] == '\n'))
    {
        if (prog[p] == '\n')
            row++;
        p++;
    }
    if (p >= strlen(prog))
    {
        syn = 0;
        return;
    }
    ch = prog[p++];

    // 进行标示符或者关键字的识别
    if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
    {
        m = 0;
        while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'))
        {
            token[m++] = ch;
            if (p >= strlen(prog))
                break;
            ch = prog[p++];
        }
        token[m] = '\0';
        if (p < strlen(prog))
            p--;
        syn = 2;
        for (n = 0; n < 10; n++) // 更新关键字表长度
        {
            if (strcmp(token, rwtab[n]) == 0)
            {
                syn = 1;
                break;
            }
        }
    }
    // 进行数字的识别
    else if (ch >= '0' && ch <= '9')
    {
        sum = 0;
        while (ch >= '0' && ch <= '9')
        {
            sum = sum * 10 + (ch - '0');
            if (p >= strlen(prog))
                break;
            ch = prog[p++];
        }
        if (p < strlen(prog))
            p--;
        syn = 3;
    }
    // 进行其他字符的识别
    else
    {
        switch (ch)
        {
        case '<':
            m = 0;
            token[m++] = ch;
            if (p < strlen(prog) && prog[p] == '<')
            {
                token[m++] = prog[p++];
                syn = 4;
            }
            else
            {
                syn = 4;
                p--;
            }
            break;
        case '>':
            m = 0;
            token[m++] = ch;
            if (p < strlen(prog) && prog[p] == '=')
            {
                token[m++] = prog[p++];
                syn = 4;
            }
            else
            {
                syn = 4;
                p--;
            }
            break;
        case ':':
            m = 0;
            token[m++] = ch;
            if (p < strlen(prog) && prog[p] == '=')
            {
                token[m++] = prog[p++];
                syn = 4;
            }
            else
            {
                syn = 4;
                p--;
            }
            break;
        case '*':
            syn = 4;
            token[0] = ch;
            break;
        case '/':
            syn = 4;
            token[0] = ch;
            if (p < strlen(prog) && prog[p] == '/') {
                token[1] = '/';
                syn = 5; // 注释符号作为界符处理
                p++;
            }
            break;
        case '+':
            syn = 4;
            token[0] = ch;
            break;
        case '-':
            syn = 4;
            token[0] = ch;
            break;
        case '=':
            syn = 4;
            token[0] = ch;
            break;
        case ';':
            syn = 5;
            token[0] = ch;
            break;
        case ',':
            syn = 5;
            token[0] = ch;
            break;
        case '(':
            syn = 5;
            token[0] = ch;
            break;
        case ')':
            syn = 5;
            token[0] = ch;
            break;
        case '{':
            syn = 5;
            token[0] = ch;
            break;
        case '}':
            syn = 5;
            token[0] = ch;
            break;
        case '#':
            syn = 0;
            token[0] = ch;
            break;
        case '"':
            syn = 5;
            token[0] = ch;
            break;
        default:
            syn = -1;
            break;
        }
    }
}

int main()
{
    // 输入
    p = 0;
    cout << "Please input string:" << endl;
    do
    {
        cin.get(ch);
        prog[p++] = ch;
    } while (ch != '#');
    prog[p] = '\0';
    p = 0;

    // 输出
    do
    {
        scaner();
        switch (syn)
        {
        case 0:
            break;
        case 3:
            cout << "(" << syn << "," << sum << ")" << endl;
            break;
        case -1:
            cout << "Error in row " << row << "!" << endl;
            break;
        default:
            cout << "(" << syn << "," << token << ")" << endl;
            break;
        }
    } while (syn != 0);
    return 0;
}    

题目描述

5.3 词法分析器设计与实现实验报告

任务描述

本实验旨在加深对词法分析器工作流程的理解,掌握基础词法分析实现方法,使用编程语言编写简易词法分析程序,完成对简单代码段的字符扫描、单词拆分与类型识别,实现自动化词法检测与错误提示。

相关知识

词法分析的基本知识

词法分析器(Lexer)是编译过程的首个核心模块,核心作用为从左至右逐字符扫描源程序字符流,依据编程语言构词规则,拆分并识别独立单词符号。

核心功能:

  1. 顺序读取源程序字符流,过滤空白符、换行等无效字符;
  2. 识别具有独立语义的单词单元;
  3. 输出单词分类结果,或反馈词法错误信息。

单词符号五大分类:

  1. 标识符:以字母开头,由字母、数字组成,用于定义变量、函数名;
  2. 关键字(基本字) :语言预定义保留字,如ifintwhile,不可自定义使用;
  3. 常数:包含整型、实型等数值常量;
  4. 运算符 :算术、关系、逻辑运算符(+>=&& 等);
  5. 界符 :语句分隔符号,如;(){},

词法分析统一采用二元式存储格式(单词种别码,单词属性值),通过数字编码区分单词类型,为后续语法分析提供标准化数据。

实验步骤

  1. 定义符号规则与关键字表

    预先定义系统关键字集合、合法运算符、界符集合,划分三类识别逻辑:关键字/标识符识别、数字识别、特殊符号识别。

  2. 分类编写单词识别逻辑

  • 字母开头字符:持续读取后续字母与数字,拼接完整单词,遍历关键字表匹配,区分关键字自定义标识符
  • 数字开头字符:连续读取数字字符,拼接完整数值,判定为常数;
  • 特殊符号字符:通过分支判断,区分单字符、双字符运算符与各类界符,完成符号归类。
  1. 源程序读取与逐行扫描

    读取完整源代码存入字符数组,设置位置指针逐字符遍历,自动过滤空格、换行,循环调用扫描函数,直至读取结束符。

  2. 结果输出与错误处理

    识别合法单词后,以(种别码, 单词值)格式输出;对非法字符、格式错误内容,输出行数与错误提示,保证程序持续运行。

编程要求

基于给定 C/C++ 代码框架,补全三大核心模块:

  1. 关键字与标识符识别代码块;
  2. 数字常量识别代码块;
  3. 运算符、界符等特殊字符识别代码块;
    编译运行程序,实现对测试代码的全自动词法分析,保证识别结果准确、错误提示有效。

测试说明

测试输入

cpp 复制代码
using namespace std;
int main()
{
    int year;
    cout << "hello" << endl;
    return 0;
}
#

运行要求

程序逐一对代码内关键字、标识符、常数、运算符、界符进行拆分,输出标准化二元式结果,正确区分各类单词种别,无程序崩溃、无识别遗漏。


相关推荐
skilllite作者6 小时前
Warp 新手极速上手与部署指南
java·前端·笔记·安全·agentskills
木木_王6 小时前
嵌入式Linux学习 | 数据结构(Day06)全解:线性表 + 栈队列 + 静态库 / 动态库(原理 + 代码 + 编译实战 + 易错点)
linux·数据结构·笔记·学习
-Springer-6 小时前
STM32 学习 —— 个人学习笔记11-2(SPI 通信外设 & 硬件 SPI 读写 W25Q64)
笔记·stm32·学习
中屹指纹浏览器6 小时前
浏览器指纹内核级篡改技术实现与风险防御
经验分享·笔记
天天爱吃肉82187 小时前
笔记:同步电机调试时电角度校正方法说明
大数据·人工智能·笔记·功能测试·嵌入式硬件·汽车
峥无7 小时前
Linux 文件系统底层探秘:磁盘物理结构→inode→Ext 架构全链路
linux·运维·笔记
阿Y加油吧7 小时前
二刷 LeetCode:118. 杨辉三角 & 198. 打家劫舍 复盘笔记
笔记·算法·leetcode
70asunflower7 小时前
半导体产业的经济逻辑、技术瓶颈与AI芯片格局:一份学习笔记
人工智能·笔记·学习