生成C代码
编译器本质上就是一门语言生成另一门语言的过程。
V目前的编译思路是:编译生成对应的C代码,然后调用C编译器来生成可执行文件。
V语言的开发重点在编译器前端,C就是编译器后端。
现在也生成了js代码,估计也会生成wasm代码。
或者考虑基于LLVM,生成LLVM IR。
或者直接生成机器码。
生成C代码
使用-o参数就可以,把当前目录的main.v代码生成main.c代码:
v -o main.c ./main.v V代码编译后,生成单个文件的C代码。
通过查看V代码生成的C代码,可以更容易理解V编译器是如何编译的。
基本类型对应
V的基本类型通过C的类型别名typedef来实现:
//int类型没有类型别名,直接就是C的int类型
typedef int64_t i64;
typedef int16_t i16;
typedef int8_t i8;
typedef uint64_t u64;
typedef uint32_t u32;
typedef uint8_t u8;
typedef uint16_t u16;
//typedef uint8_t byte;
typedef uint32_t rune;
typedef size_t usize;
typedef ptrdiff_t isize;
#ifndef VNOFLOAT
typedef float f32;
typedef double f64;
#else
typedef int32_t f32;
typedef int64_t f64;
#endif
typedef int64_t int_literal;
#ifndef VNOFLOAT
typedef double float_literal;
#else
typedef int64_t float_literal;
#endif
typedef unsigned char* byteptr; //字节指针
typedef void* voidptr;//通用指针
typedef char* charptr; //C字符指针
typedef u8 array_fixed_byte_300 [300];
typedef struct sync__Channel* chan;
#ifndef __cplusplus
#ifndef bool
#ifdef CUSTOM_DEFINE_4bytebool
typedef int bool;
#else
typedef u8 bool; //布尔类型在C里面默认通过u8类型来实现,1字节
#endif
#define true 1 //true是整数常量1
#define false 0 //false是整数常量0
#endif
#endif代码对照表
常量
int类型常量,生成C的宏定义,其他类型常量,生成C的全局变量。这样就很好理解,V语言中的常量可以是任何类型,跟变量一样,甚至可以是函数调用的结果。
常量的不可修改,由V编译器负责检查。
V代码:
C代码:
枚举
V的枚举生成等价的C枚举,枚举的pub属性在C中没有对应,由V编译器负责控制。
V代码:
C代码:
模块
V的模块,在生成对应C代码后,只是对应元素名称的前缀,毕竟C语言中没有模块的概念。
常量,结构体,接口,类型等一级元素生成C代码后的名称规则是:模块名__名称,用双下划线区隔。例如:mymodule模块中的add()函数生成C代码后的名称为:mymodule__add()。
结构体的方法等二级元素生成C代码后的名称规则是:模块名__类名_方法名,用单下划线区隔。例如:模块中的Color结构体的str()方法生成C代码后的名称为:mymodule__Color_str()。
V代码:
C代码:
函数
模块中的函数,生成等价的C的函数。
V代码:
C代码:
函数defer语句
C没有defer语句,V编译的时候就是把函数中的defer语句去掉,然后按后进先出的顺序,放在defer语句之后的所有return语句前,以及函数末尾,有各自独立的代码块。
V代码:
C代码:
函数不确定个数参数
不确定参数就是根据返回值的类型,编译时动态生成一个C数组,作为函数的最后一个参数。
V代码:
C代码:
函数多返回值
C的函数返回值只有1个,V的函数多返回值,就是把多返回值的组合,编译时动态生成一个结构体,然后返回结构体。并且生成的返回值组合的结构体,还可以给其他相同类型的多返回值的函数公用。
V代码:
C代码:
数组
V的数组是用struct来实现的,生成C代码也是struct。
V代码:
C代码:
字符串
V的字符串是用struct来实现的,生成C代码也是struct。
V代码:
C代码:
字典
V的字典是用struct来实现的,生成C代码也是struct。
V代码:
C代码:
结构体
生成对应的C结构体:
V代码:
C代码:
结构体方法
结构体方法生成C函数,只是函数的第一个参数是对应结构体类型的指针,
生成的C函数命名规则是:结构体名_方法名。
V代码:
C代码:
结构体访问控制
访问控制在C代码中没有体现,全部在V编译器中控制。
V代码:
C代码:
流程控制语句
条件
if语句,生成C if语句:
V代码:
C代码:
if表达式语句,生成C的三元运算符 ? :
V代码:
C代码:
分支
match语句,生成C的if-else if-else语句。
V代码:
C代码:
match表达式语句,生成嵌套的三元运算符语句。
V代码:
C代码:
循环
步长:for i=0;i<100;i++ {}
V代码:
C代码:
循环:for i<100 {}
V代码:
C代码:
无限循环:for {}
V代码:
C代码:
遍历:for i in xxx {}
V代码:
C代码:
类型定义
类型定义type生成C的类型别名typedef。
V代码:
C代码:
接口
在编译时穷举所有实现了接口的结构体,构造接口的结构体,接口结构体包含了一个匿名联合体和类型id。然后为每一个实现了接口的联合体生成一个创建函数,返回接口的结构体,并通过类型id标识具体的类型。
V代码:
C代码:
泛型
泛型函数/方法
编译时,穷举所有泛型函数实际调用的所有类型,为每一个实际调用的类型,生成对应版本的C函数。
V代码:
C代码:
泛型结构体
编译时,穷举所有泛型类型实际调用的所有类型,为每一个实际调用的类型,生成对应版本的C结构体。
V代码:
C代码:
泛型接口
编译时,穷举所有泛型接口实际调用的所有类型,为每一个实际调用的类型,生成对应版本的C结构体。
V代码:
C代码:
泛型联合类型
编译时,也是穷举所有实际调用的类型,生成对应的C结构体。
V代码:
C代码:
错误处理
跟函数的多返回值类似,编译器为每一种返回类型,生成一个对应类型的结构体,全局共用。
V代码:
C代码:
联合类型
联合类型,使用C结构体,结构体中包含一个匿名联合体,以及类型id。并且为联合类型的每一个类型,自动生成一个创建函数。
V代码:
C代码:
运算符重载
编译时,将重载运算符,转换成普通C函数。
V代码:
C代码:
条件编译
判断操作系统
V代码:
C代码:
判断操作系统位数
V代码:
C代码:
判断大端序/小端序
V代码:
C代码:
内联汇编代码
生成等价的C内联汇编代码:
V代码:
C代码:
最后更新于
这有帮助吗?