头歌编译原理实验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;
}
#

运行要求

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


相关推荐
旅僧23 分钟前
机械臂学习笔记(更新中)
笔记·学习
qingwufeiyang_53036 分钟前
Python学习笔记3-项目实战-AI应用
笔记·学习
智者知已应修善业43 分钟前
【proteus 74160实现模60计数器模41计数器】2024-5-27
驱动开发·经验分享·笔记·硬件架构·proteus·硬件工程
墨白曦煜1 小时前
算法实战笔记:空间换时间的黑魔法——单调栈全景解析(十一)
java·笔记·算法
问心无愧05131 小时前
ctf show web入门157 158
前端·笔记
闪闪发亮的小星星1 小时前
STK-03-通信卫星方向最常遇到的场景
笔记
.千余1 小时前
【C++】C++继承入门(上):继承语法与基本特性详解
开发语言·c++·笔记·学习·其他
问心无愧05131 小时前
ctf show web入门159
前端·笔记
NULL指向我2 小时前
TMS320F28379D笔记4:CAN通信的收发配置
笔记
疯狂打码的少年2 小时前
【程序语言与编译】文法的分类(0-3型,乔姆斯基体系)
人工智能·笔记·分类·数据挖掘