生成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代码:

最后更新于

这有帮助吗?