当前位置: 首页 > news >正文

洛谷P11738 [集训队互测 2015] 未来程序改

懒得写这么大的模拟了,想学的可以去看看我的项目QAQ

很显然,这是一道编译原理题目(我的专项awa)

编译原理 - 编译器结构

首先,编译器由Lexer,Parser,(Codegen,Optimizer)组成
然而严格来讲这道题需要的是解析器,那么结构变成:
Lexer, Parser, Interpreter

Lexer

Lexer负责生成tokens(符号表),就比如说:

#include<iostream>
#include<cstdio>
using namespace std;int main() {return 0;
}

依据题意,你可以舍弃前三行,然后利用正则表达式进行搜索。
很显然你看到了题目给你的上下文无关法里面有:

NAME ::= 仅包含大小写字母、数字、下划线的非空字符串,且不以数字开头。

转换为正则表达式就是:

[a-zA-Z_][a-zA-Z0-9_]*

还有整数

INT_CONSTANT ::= 仅包含数字的非空字符串,且不以0开头,或这个字符串就是0。

转换为正则表达式就是:

[1-9][0-9]*|0

然后你就可以利用std::regex正则表达式进行搜索了。

当然,你还要使用regex搜索一些关键字:

int, if, for, while, return, cin, cout, endl

以及一些符号(自己看上下文无关法)

Parser

Parser负责生成AST(抽象语法树),那么你需要根据上下文无关法生成对应的语法树节点。

首先你需要定义一个节点类,然后根据上下文无关法生成对应的节点,比如:

// shared_ptr是C++11引入的智能指针,用于自动管理内存
#include<memory>
using namespace std;
class Node{public:AstType type; // 节点类型Token token; // 节点对应的tokenvector<shared_ptr<Node>> children; // 子节点Node(AstType type, Token token) : type(type), token(token) {} // 构造函数
};

然后你需要根据上下文无关法生成对应的节点,比如:

// 生成一个变量声明节点
shared_ptr<Node> varDecl(Token name, Token type) {shared_ptr<Node> node(new Node(AstType::VarDecl, name));node->children.push_back(make_shared<Node>(AstType::Type, type));return node;
}

然后自上而下依次解析递归生成语法树。(还是那句话,自己看上下文无关法)
比如:

#include<iostream>
#include<cstdio>
using namespace std;int main() {return 3*1-2;
}

对应的语法树就是:

intmain[] // 没有参数,所以是空数组(STATEMENTS)return(EXPRESSION)*31-2

Interpreter

Interpreter负责解释AST,那么你需要根据上下文无关法解释对应的语法树节点。

首先你需要写一个虚拟机进行输入输出流控制:

class VM {public:// cin从输入流中读取一个整数// cout输出一个整数到输出流中// putchar输出一个字符到输出流中// endl输出一个换行符到输出流中
}

当然,虚拟机的属性是static

假设你现在有N个整数要输入,那么你可以:

deque<int> istream; // 输入流
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) {int x;scanf("%d", &x);istream.push_back(x);
}

然后你就可以在VM中写一个cin函数了:

int cin() {int x = istream.front();istream.pop_front();return x;
}

在解析树中,你可以用类似DFS的方法来解释语法树节点。比如:

void Interpreter::visit(Node* node) {switch (node->type) {case AstType::Program:visitProgram(node);break;case AstType::VarDecl:visitVarDecl(node);break;case AstType::Type:visitType(node);break;/*...*/}
}

visitProgram中,你需要遍历语法树中的所有VarDecl节点,然后调用visitVarDecl来解释这些节点。在visitVarDecl中,你需要解释Type节点,然后解释Identifier节点,最后解释Expression节点。
当你使用cin或者cout时,你需要调用VM中的对应函数。

最后,你需要写一个main函数来运行你的解释器:

int main() {// 读取输入// 构造语法树// 解释语法树return 0;
}

结语

由于代码过长(且过于麻烦),这里就不贴了(实则没写)。如果有对编译原理感兴趣的童鞋可以去看看我自己写的编程语言:
Cabbagelang

http://www.gsyq.cn/news/15687.html

相关文章:

  • 实用指南:[创业之路-645]:手机属于通信?还是属于消费类电子?还是移动互联网?
  • ai提交消息常用的 chore,原来是个单词(琐事/零散任务)+约定,用于非功能性提交
  • 多项式定理
  • 详细介绍:Kafka09-速答-尚硅谷
  • 前端安全障碍深度解析:从原理到实践的全方位防护指南
  • node菜单服务引起的后台异常表象到运维释放从库的数据库连接及驱动修改配置,重新部署生效
  • 深入解析:从零起步学习Redis || 第四章:Cache Aside Pattern(旁路缓存模式)以及优化策略
  • 详细介绍:SpringCloud API Gateway2.0如何解决docker中应用间IP漂移的正确手法
  • 251004
  • gradle Cause: zip END header not found
  • 【性质】CF689D Friends and Subsequences
  • Arduino+数码管 = 量电压 | A+B problem | alphabet
  • 详细介绍:【数据库知识】TxSQL 主从数据库同步底层原理深度解析
  • 完整教程:AI时代如何高效学习Python:从零基础到项目实战de封神之路(2025升级版)
  • cannot resolve method add in T 及 T 泛型类型生成Excel文件,区别是数据Model不同
  • 测试环境elasticSearch数据泄露排查
  • PocoEmit遥遥领先于AutoMapper之打通充血模型的任督二脉
  • Linux基础开发工具 --- vim - 详解
  • 【Clion】【文件编码】Clion内置控制台中文字体乱码的解决方案及编码格式调整
  • Qt纯代码实现智能安防集中管理平台/楼宇对讲管理系统/门禁管理/视频监控
  • DaYe-PhotoStudio-2 v2.0.0 安装教程(64位/AMD64)详细步骤
  • 威胁狩猎实战:终端攻击行为分析与检测
  • 2024年全国大学生信息安全竞赛安徽省赛网络高效的系统建设与运维赛项-网络构建真题
  • 实用指南:基于Hadoop+Spark的人体体能数据分析与可视化系统开源实现
  • 基于Hadoop的肾脏疾病风险分析系统架构设计精髓 - 实践
  • const在for用不了
  • 某工程师入职华为,职级比较高,但还看不懂代码,有点尴尬
  • 使用Silobase在几分钟内快速部署后端API
  • 【光照】[各向异性]在UnityURP中的实现
  • 基于HAL库和中断的LED流水灯