编译原理实战:基于 Python 3.11 实现简易四则运算词法分析器(附完整代码)
编译原理实战基于Python 3.11构建四则运算词法分析器词法分析作为编译器的第一道工序其核心任务是将字符流转换为有意义的单词序列。本文将以Python 3.11为开发环境从零实现一个能够识别四则运算表达式包含数字、运算符和括号的词法分析器。通过这个实践项目您将深入理解有限自动机(DFA)的理论如何转化为实际代码。1. 词法分析器设计基础词法分析器的本质是模式识别引擎需要处理以下核心问题如何定义各类词法单元token的模式如何高效扫描输入字符串如何处理边界条件和错误情况在四则运算场景中我们需要识别的token类型包括整数如42浮点数如3.14运算符,-,*,/括号(,)空白字符通常被忽略1.1 有限自动机的Python实现策略确定有限自动机(DFA)的实现有两种典型方式状态转移表法用二维表格显式表示状态转移条件分支法用代码逻辑隐式表达状态转移我们将采用第二种方式因为它更符合Python的动态特性代码也更具可读性。以下是关键状态定义from enum import Enum, auto class State(Enum): START auto() IN_INTEGER auto() IN_FLOAT auto() IN_OPERATOR auto() IN_PAREN auto() ERROR auto()1.2 正则表达式与手工实现的权衡虽然Python的re模块可以快速实现词法分析但手工实现DFA更有教学价值更直观展示状态转移过程更容易添加自定义错误处理性能通常更优避免正则引擎开销下表对比两种实现方式的特性特性正则表达式实现手工DFA实现开发速度快慢运行效率中等高可调试性差好错误处理灵活性有限完全可控教学价值低高2. 核心实现解析2.1 Token类型定义首先定义词法单元的数据结构from dataclasses import dataclass from typing import Literal dataclass class Token: type: Literal[INTEGER, FLOAT, OPERATOR, PAREN] value: str position: int # 在源字符串中的起始位置2.2 词法分析器类框架构建词法分析器的主框架class Lexer: def __init__(self, text: str): self.text text self.pos 0 self.current_char self.text[self.pos] if self.text else None def advance(self): 移动到下一个字符 self.pos 1 if self.pos len(self.text): self.current_char self.text[self.pos] else: self.current_char None def skip_whitespace(self): 跳过空白字符 while self.current_char is not None and self.current_char.isspace(): self.advance() def get_next_token(self) - Token: 获取下一个token while self.current_char is not None: if self.current_char.isspace(): self.skip_whitespace() continue # 整数和浮点数识别 if self.current_char.isdigit(): return self.handle_number() # 运算符识别 if self.current_char in -*/: token Token(OPERATOR, self.current_char, self.pos) self.advance() return token # 括号识别 if self.current_char in (): token Token(PAREN, self.current_char, self.pos) self.advance() return token raise Exception(fInvalid character {self.current_char} at position {self.pos}) return None # 输入结束2.3 数字识别算法数字识别是词法分析中最复杂的部分需要处理以下情况纯整数123浮点数3.14科学计数法本例暂不实现def handle_number(self) - Token: 处理数字字面量整数或浮点数 start_pos self.pos num_str has_decimal False while self.current_char is not None and (self.current_char.isdigit() or self.current_char .): if self.current_char .: if has_decimal: raise Exception(fMultiple decimal points in number at position {self.pos}) has_decimal True num_str self.current_char self.advance() # 检查数字有效性 if num_str.endswith(.): raise Exception(fTrailing decimal point at position {self.pos}) return Token(FLOAT if has_decimal else INTEGER, num_str, start_pos)3. 高级功能扩展3.1 错误恢复机制健壮的词法分析器应该能够从错误中恢复而不是遇到第一个错误就崩溃。我们添加错误恢复逻辑def get_next_token(self) - Token: try: # 原有识别逻辑... except Exception as e: print(fLexical error: {e}) # 跳过当前字符尝试恢复 self.advance() return self.get_next_token() # 递归调用注意实际项目中可能需要限制递归深度3.2 位置跟踪增强为支持更好的错误报告增强位置跟踪功能dataclass class Position: line: int column: int dataclass class Token: type: str value: str position: Position # 替换原来的整数位置 class Lexer: def __init__(self, text: str): self.line 1 self.column 1 # 其余初始化... def advance(self): if self.current_char \n: self.line 1 self.column 1 else: self.column 1 # 其余advance逻辑...4. 完整实现与测试4.1 完整词法分析器代码from dataclasses import dataclass from typing import Literal, Optional dataclass class Position: line: int column: int dataclass class Token: type: Literal[INTEGER, FLOAT, OPERATOR, PAREN, EOF] value: str position: Position class Lexer: def __init__(self, text: str): self.text text self.pos 0 self.line 1 self.column 1 self.current_char self.text[self.pos] if self.text else None def advance(self): if self.current_char \n: self.line 1 self.column 1 else: self.column 1 self.pos 1 if self.pos len(self.text): self.current_char self.text[self.pos] else: self.current_char None def skip_whitespace(self): while self.current_char is not None and self.current_char.isspace(): self.advance() def handle_number(self) - Token: start_pos Position(self.line, self.column) num_str has_decimal False while self.current_char is not None and (self.current_char.isdigit() or self.current_char .): if self.current_char .: if has_decimal: raise Exception(fMultiple decimal points at {self.line}:{self.column}) has_decimal True num_str self.current_char self.advance() if num_str.endswith(.): raise Exception(fTrailing decimal point at {self.line}:{self.column}) return Token(FLOAT if has_decimal else INTEGER, num_str, start_pos) def get_next_token(self) - Optional[Token]: try: while self.current_char is not None: if self.current_char.isspace(): self.skip_whitespace() continue if self.current_char.isdigit(): return self.handle_number() if self.current_char in -*/: token Token(OPERATOR, self.current_char, Position(self.line, self.column)) self.advance() return token if self.current_char in (): token Token(PAREN, self.current_char, Position(self.line, self.column)) self.advance() return token raise Exception(fUnexpected character {self.current_char} at {self.line}:{self.column}) return Token(EOF, , Position(self.line, self.column)) except Exception as e: print(fError: {e}) self.advance() return self.get_next_token() def tokenize(text: str) - list[Token]: lexer Lexer(text) tokens [] while (token : lexer.get_next_token()) is not None: if token.type ! EOF: tokens.append(token) return tokens4.2 测试案例验证词法分析器处理各种情况的能力# 测试混合表达式 expression 3.14 * (42 6.28) / 0.5 tokens tokenize(expression) for token in tokens: print(f{token.type:8} {token.value:6} at {token.position.line}:{token.position.column}) # 预期输出 # FLOAT 3.14 at 1:1 # OPERATOR * at 1:6 # PAREN ( at 1:8 # INTEGER 42 at 1:9 # OPERATOR at 1:12 # FLOAT 6.28 at 1:14 # PAREN ) at 1:18 # OPERATOR / at 1:20 # FLOAT 0.5 at 1:225. 性能优化与生产级考量5.1 内存效率优化对于大型源代码文件可以优化内存使用使用生成器逐步产生token而非构建完整列表避免不必要的字符串拼接改进的token生成方法def tokenize_generator(text: str): lexer Lexer(text) while (token : lexer.get_next_token()) is not None: if token.type ! EOF: yield token5.2 运算符扩展实际编译器需要支持更多运算符类型OPERATORS { : PLUS, -: MINUS, *: MUL, /: DIV, ^: POW, %: MOD, : ASSIGN, # 可以继续添加更多运算符 } # 在get_next_token方法中修改运算符识别 if self.current_char in OPERATORS: op self.current_char # 处理多字符运算符如, 等 self.advance() if op (self.current_char or ) in {, , -, *, /}: op self.current_char self.advance() return Token(OPERATOR, op, Position(self.line, self.column))5.3 与语法分析器的集成词法分析器通常与语法分析器协同工作可以通过以下方式改进接口class Parser: def __init__(self, lexer: Lexer): self.lexer lexer self.current_token self.lexer.get_next_token() def eat(self, token_type): if self.current_token.type token_type: self.current_token self.lexer.get_next_token() else: raise Exception(fExpected {token_type}, got {self.current_token.type}) def parse(self): # 解析逻辑... pass通过这个实践项目我们不仅实现了四则运算的词法分析器还展示了如何将编译原理中的DFA理论转化为实际代码。这种实现方式虽然比使用正则表达式更繁琐但提供了更好的可扩展性和更深入的学习体验。

相关新闻

RVC语音克隆终极指南:10分钟创建专属AI声音模型

RVC语音克隆终极指南:10分钟创建专属AI声音模型

RVC语音克隆终极指南&#xff1a;10分钟创建专属AI声音模型 【免费下载链接】Retrieval-based-Voice-Conversion-WebUI Easily train a good VC model with voice data < 10 mins! 项目地址: https://gitcode.com/GitHub_Trending/re/Retrieval-based-Voice-Conversion-We…

2026/7/13 23:18:07阅读更多 →
Hotkey Detective:三分钟找出Windows热键冲突的终极侦探工具

Hotkey Detective:三分钟找出Windows热键冲突的终极侦探工具

Hotkey Detective&#xff1a;三分钟找出Windows热键冲突的终极侦探工具 【免费下载链接】hotkey-detective A small program for investigating stolen key combinations under Windows 7 and later. 项目地址: https://gitcode.com/gh_mirrors/ho/hotkey-detective 你…

2026/7/13 23:18:07阅读更多 →
直流负载管理方案:欧姆龙G6D-ASI与TI TM4C129LNCZAD的工业级应用

直流负载管理方案:欧姆龙G6D-ASI与TI TM4C129LNCZAD的工业级应用

1. 直流负载管理的行业痛点与解决方案在工业自动化、新能源发电和电力电子领域&#xff0c;直流负载管理一直是个棘手的技术难题。传统方案通常采用机械式接触器或纯MOSFET开关&#xff0c;前者存在响应速度慢、体积庞大的问题&#xff0c;后者则面临导通损耗高、散热设计复杂的…

2026/7/13 23:18:07阅读更多 →
XUnity.AutoTranslator 游戏实时翻译插件:从原理到实战的完整指南

XUnity.AutoTranslator 游戏实时翻译插件:从原理到实战的完整指南

1. 项目概述&#xff1a;当游戏语言成为一堵墙作为一名玩了十几年日系、欧美独立游戏的“老油条”&#xff0c;我太懂那种面对一款心仪已久、画风玩法都戳中G点的游戏&#xff0c;却因为语言不通而望而却步的痛了。尤其是那些基于Unity引擎开发的、体量不大但内容精良的作品&am…

2026/7/14 0:08:18阅读更多 →
Ollama 本地部署 Qwen3 + SpringAI Alibaba 快速入门

Ollama 本地部署 Qwen3 + SpringAI Alibaba 快速入门

标签&#xff1a;Ollama、Qwen3、SpringAI Alibaba、ChatClient、流式响应、Java AI一、前言 上一篇介绍了阿里云百炼云端模型和 OpenAI 接口规范。 本篇进入实操环节&#xff1a; 使用 Ollama 在本地部署 Qwen3 大模型在 Spring Boot 中集成 SpringAI Alibaba同时配置云端&…

2026/7/14 0:08:18阅读更多 →
SpringAI AlibabaRAGMilvus 笔记(一):课程导读与阿里云百炼云模型调试

SpringAI AlibabaRAGMilvus 笔记(一):课程导读与阿里云百炼云模型调试

SpringAI Alibaba&RAG&Milvus 笔记&#xff08;一&#xff09;&#xff1a;课程导读与阿里云百炼云模型调试 标签&#xff1a;SpringAI Alibaba、阿里云百炼、大模型、OpenAI 接口规范、Java AI 一、前言 AI 大模型时代&#xff0c;Java 工程师也能用熟悉的 Spring 生…

2026/7/14 0:08:18阅读更多 →
AI Agent 系统架构:Planner、Executor、Memory、Tools 如何协作

AI Agent 系统架构:Planner、Executor、Memory、Tools 如何协作

一个真正好用的 AI Agent&#xff0c;不是“一个更会聊天的大模型”。它更像一个小型协作系统&#xff1a;有人负责想清楚怎么做&#xff0c;有人负责一步步执行&#xff0c;有地方保存上下文&#xff0c;还有一组工具连接外部世界。 如果把 Agent 只理解成“LLM Prompt”&…

2026/7/14 0:08:18阅读更多 →
【高阶·融合】混沌工程与 AI 韧性验证深度解析:从故障注入到推理服务弹性的高可用架构

【高阶·融合】混沌工程与 AI 韧性验证深度解析:从故障注入到推理服务弹性的高可用架构

【高阶融合】混沌工程与 AI 韧性验证深度解析:从故障注入到推理服务弹性的高可用架构 专栏:《AI 工程与安全深度实战》 第7轮第3篇 核心痛点:AI 推理服务的失效模式远超传统云原生应用——GPU 静默数据损坏(SDC)会无声腐蚀模型权重、KV Cache OOM 会拖垮连续批处理、负载升…

2026/7/14 0:08:18阅读更多 →
DeepSeek提示词效果暴跌预警:当LLM置信度低于0.62时,必须启用的4层动态重写机制

DeepSeek提示词效果暴跌预警:当LLM置信度低于0.62时,必须启用的4层动态重写机制

更多请点击&#xff1a; https://codechina.net 第一章&#xff1a;DeepSeek提示词效果暴跌预警&#xff1a;当LLM置信度低于0.62时&#xff0c;必须启用的4层动态重写机制 当DeepSeek-R1或DeepSeek-V3模型返回的token级置信度&#xff08;logits softmax归一化后最大概率值&a…

2026/7/14 0:03:18阅读更多 →
VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比&#xff1a;全局安装 vs 项目本地安装的4个关键差异当你在VSCode中启动一个新的TypeScript项目时&#xff0c;第一个技术决策往往从安装方式开始。这个看似简单的选择——全局安装还是项目本地安装——实际上会深刻影响你的开发流程、团队协作和…

2026/7/13 4:47:19阅读更多 →
智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件&#xff1a;5分钟实现自动化学习的智能助手 【免费下载链接】zhihuishu 智慧树刷课插件&#xff0c;自动播放下一集、1.5倍速度、无声 项目地址: https://gitcode.com/gh_mirrors/zh/zhihuishu 智慧树刷课插件是一款专为智慧树在线教育平台设计的Chrome浏…

2026/7/13 0:50:34阅读更多 →
Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL&#xff1a;跨平台游戏模组获取的终极解决方案 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 你是否在GOG或Epic Games Store购买了心仪的游戏…

2026/7/13 4:52:09阅读更多 →
【Cursor数据库安全红线】:自动执行SQL前必须校验的6项权限策略,金融级项目已强制落地

【Cursor数据库安全红线】:自动执行SQL前必须校验的6项权限策略,金融级项目已强制落地

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;Cursor数据库安全红线概览 Cursor 作为一款基于 AI 的智能编程助手&#xff0c;其本地数据库&#xff08;SQLite 存储&#xff09;承载着用户代码片段、会话历史、自定义规则及敏感上下文信息。理解其安…

2026/7/14 0:03:18阅读更多 →
【Notion AI写作避坑白皮书】:基于127份真实用户失败案例,总结6大致命误用陷阱

【Notion AI写作避坑白皮书】:基于127份真实用户失败案例,总结6大致命误用陷阱

更多请点击&#xff1a; https://codechina.net 第一章&#xff1a;Notion AI写作辅助的底层能力边界认知 Notion AI 并非通用大语言模型的直接封装&#xff0c;而是基于 Llama 系列与自研微调模型构建的轻量化推理服务&#xff0c;其输入上下文窗口严格限制在 8192 token&…

2026/7/14 0:03:18阅读更多 →
AI Agent数据越界行为如何被精准溯源?——基于GDPR/CCPA双合规的5层审计框架实战指南

AI Agent数据越界行为如何被精准溯源?——基于GDPR/CCPA双合规的5层审计框架实战指南

更多请点击&#xff1a; https://kaifayun.com 第一章&#xff1a;AI Agent数据越界行为的合规性挑战与溯源必要性 AI Agent在自主执行任务过程中&#xff0c;可能因提示注入、上下文污染或权限配置缺陷&#xff0c;无意或有意访问、缓存、传输受保护数据&#xff08;如PII、G…

2026/7/14 0:03:18阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时&#xff0c;发现推理速度只有可怜的 1-2 FPS&#xff0c;而别人的演示视频却能跑到 30 FPS 以上&#xff0c;那么问题很可能不在模型本身&#xff0c;而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后&#xff0c;会直接使用官方示例…

2026/7/13 4:21:17阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一&#xff1a;为什么你需要了解 Coze 和 Dify&#xff1f;如果你对 AI 应用开发感兴趣&#xff0c;但一看到“大模型”、“智能体”、“工作流”这些词就头疼&#xff0c;觉得门槛太高&#xff0c;那这篇文章就是为你准备的。很多开发者&#xff0c;包括我自己&#…

2026/7/13 4:08:53阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会&#xff1a;配图一直是个让人头疼的问题。2026年&#xff0c;AI生图工具已经非常成熟了&#xff0c;但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1&#xff1a;速度之王2026年6月11日&#xff0c…

2026/7/12 21:43:43阅读更多 →