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)是编译过程的首个核心模块,核心作用为从左至右逐字符扫描源程序字符流,依据编程语言构词规则,拆分并识别独立单词符号。
核心功能:
- 顺序读取源程序字符流,过滤空白符、换行等无效字符;
- 识别具有独立语义的单词单元;
- 输出单词分类结果,或反馈词法错误信息。
单词符号五大分类:
- 标识符:以字母开头,由字母、数字组成,用于定义变量、函数名;
- 关键字(基本字) :语言预定义保留字,如
if、int、while,不可自定义使用; - 常数:包含整型、实型等数值常量;
- 运算符 :算术、关系、逻辑运算符(
+、>=、&&等); - 界符 :语句分隔符号,如
;、()、{}、,。
词法分析统一采用二元式存储格式 :(单词种别码,单词属性值),通过数字编码区分单词类型,为后续语法分析提供标准化数据。
实验步骤
-
定义符号规则与关键字表
预先定义系统关键字集合、合法运算符、界符集合,划分三类识别逻辑:关键字/标识符识别、数字识别、特殊符号识别。
-
分类编写单词识别逻辑
- 字母开头字符:持续读取后续字母与数字,拼接完整单词,遍历关键字表匹配,区分关键字 与自定义标识符;
- 数字开头字符:连续读取数字字符,拼接完整数值,判定为常数;
- 特殊符号字符:通过分支判断,区分单字符、双字符运算符与各类界符,完成符号归类。
-
源程序读取与逐行扫描
读取完整源代码存入字符数组,设置位置指针逐字符遍历,自动过滤空格、换行,循环调用扫描函数,直至读取结束符。
-
结果输出与错误处理
识别合法单词后,以
(种别码, 单词值)格式输出;对非法字符、格式错误内容,输出行数与错误提示,保证程序持续运行。
编程要求
基于给定 C/C++ 代码框架,补全三大核心模块:
- 关键字与标识符识别代码块;
- 数字常量识别代码块;
- 运算符、界符等特殊字符识别代码块;
编译运行程序,实现对测试代码的全自动词法分析,保证识别结果准确、错误提示有效。
测试说明
测试输入
cpp
using namespace std;
int main()
{
int year;
cout << "hello" << endl;
return 0;
}
#
运行要求
程序逐一对代码内关键字、标识符、常数、运算符、界符进行拆分,输出标准化二元式结果,正确区分各类单词种别,无程序崩溃、无识别遗漏。