Vim 实用操作

个人不喜欢看冗长的文档,但是不学习也无法获得新知,发挥vim强大的功能。 所以个人一般是看别人的概括性文章,再搜索相关不了解的功能。

Read More

向gitignore中加入tracked file

远程仓库的文件,将其加入gitignore,但是保留本地和远程的内容,后续不再更新。

因为要在x86 arch和arm mac上共用仓库,所以配置不能统一,例如cmake/vcpkg,以及build、cache等等

过程中乱用gitignore出了一些问题

Read More

龙书笔记1 - 模糊概念、杂项知识


编译器可以简单分成分析和综合两个部分

符号表是一种用于存放分析部分收集到的信息的数据结构

一个编译器的结构

  1. 词法分析 lexical analysis
    词法分析器读入源程序的字符流,产生有意义的词素(lexeme)的序列。对于每个词素,产生形式为<token-name,attribute-value>词法单元(token)作为输出

token-name是给语法分析用的抽象符号,第二个分量attribute-value指向符号表中关于这个token的条目。符号表条目的信息被语义分析和代码生成步骤使用

源程序:position=initial+rate*60

position是一个词素,被映射成词法<id,1> id是表示标识符

最终得到的token序列就是<id,1><=><id,2><+><id,3><*><60>,分隔词素的空格会被词法分析器忽略掉

<=><+><*>这样的token不需要属性值,当然也可以使用抽象符号assign

  1. 语法分析 syntax analysis/parsing

语法分析器使用token的第一个分量来创建树形的中间表示,输出词法单元流

  1. 语义分析 semantic analyzer

使用语法树和符号表中的信息来检查源程序是否和定义的语义一致,同时也收集信息放到两者中,为了之后的中间代码生成

  1. 中间代码生成

在语法分析和语义分析完成之后,很多编译器生成一个较低级或类机器语言的中间表示,比如LLVM的IR,不过IR的三种表现形式更灵活了就是说

  1. 代码优化

没什么好说的,太抽象了,没有经验撑得起来

  1. 代码生成

同上,个人对存储和寄存器的知识储备为0

  1. 符号表管理

记录使用的变量的名字,并收集和每个名字的各种属性有关的信息,这些属性提供一个名字的存储分配、类型、作用域…

  1. 将多个步骤组合成pass

每个pass读入一个文件,产生一个输出文件

  1. 编译器构造工具

  2. 语法分析器的生成器 根据一门语言的语法描述自动生成语法分析器

  3. 扫描器/词法分析器的生成器 根据一门语言的token的正则表达式描述生成词法分析器

  4. 语法制导的翻译引擎 生成一组用于遍历分析树并生成中间代码的例程

  5. 代码生成器的生成器 依据一组将中间语言的每个运算翻译成目标机上的机器语言的规则,生成一个代码生成器

  6. 数据流分析引擎

  7. 编译器构造工具集 提供可用于构造编译器不同阶段的例程的完整集合


静态与动态

  • 静态策略:编译期决定
  • 动态策略:运行期决定

环境是名字到内存位置的映射,状态是内存到值的映射

这两个映射都有动态绑定和静态绑定,动态绑定不用说,静态绑定就如设定一个全局变量时,变量的内存位置可以固定,设定一个常量时,内存对应的值可以固定

静态作用域和块结构

看到这个我人傻了,以前单知道一个作用域,但是没想到还能这么写

C++的compiler到底是有多逆天,这都能分析

int a = 1;
int b = 1;
{
int b = 2;
{
int a = 3;
cout << a << ' ' << b << '\n';
}
{
int b = 4;
cout << a << ' ' << b << '\n';
}
cout << a << ' ' << b << '\n';
}
cout << a << ' ' << b << '\n';

推荐阅读