软件说明文档.md

软件说明文档

软件名

cust

C程序转换器

功能摘要

  1. 提供命令行工具将目标 C/C++ 语言源码,转换为相应 Rust 语言代码

软件分类

linux CLI 工具

名词解释

C: 指 C/C++ 语言,后面简化称为 C

src code: 源语言,指待转换的语言,本次的指 C

AST: 抽象语法树

IR: Intermediate Representation 中间表示,与语言无关,硬件无关,容易进行优化,多级表示,丰简由人,这适合在 C to Rust 应用中使用。

应用领域

对于如军工、医疗、航天、核能领域,需要一种运行效率、内存安全、稳定性方面有严格要求的语言进行应用程序实现,当已有的 C/C++ 程序满足不了这些要求时,就需要将现有的 C/C++ 程序、工具库转换为可用的 Rust 程序。cust即可适用于此场景。

开源许可证类型

GPL v3

作品概述

背景

  • 目标:C/C++ 程序转换为 Rust 程序

作品特点

  • 结合编译原理和现有的 AI 大模型各自优势,将 C/C++ 程序转换为可用的 Rust 程序

  • 利用编译原理,src code (本次工具中为 C)转换 AST , AST 再成与 IR (中间语言的形式),再将 IR 语言转换为 Rust 语言,这样做的好处是可以利用这一思路最大程度复用代码,如 src code -> IR 这部分代码可复用于转换为其他目标语言,而 IR -> Rust code 部分代码可复用到不同的 src code -> Rust code。

    同时,C to Rust 中采用 IR 的方式有诸多优势:

    • 硬件无关:IR 设计成独立于任何特定的硬件或指令集架构(ISA),适用于多种硬件平台,也就是说转义出来的目标语言天然跨平台。
    • 容易进行优化:IR 通常设计得使得对代码进行分析和优化变得更加容易,开发路径也相对简单,易进行迭代开发。
    • 多级表示:可使用多级别的 IR,每个级别提供不同的抽象程度。

运行环境和运行步骤

编译环境

clang llvm 环境,支持 Linux ,不支持 windows

rust cargo 环境

运行环境

clang llvm 环境,支持 Linux ,不支持 windows

使用 ai 优化需要能连上通义的接口(外网)

功能描述

  • 完全使用语义解析进行 C To Rust 转换

  • 采用语义解析 C To Rust、将上下文和结果输入到 AI 大模型进行语义检查和最后的优化。

  • C 语言代码排错

    • 语法错误:这是编程中最常见的错误类型,如缺少分号、括号不匹配、错误的关键字使用等。如果代码中存在语法错误,编译器将无法正确理解代码,从而无法继续编译过程。
    • 类型错误:类型错误发生在对变量或表达式进行了不允许或预期之外的操作时,例如将整数类型赋值给字符类型变量,或对字符串执行数学运算。
    • 声明和定义错误:包括变量或函数未声明、重复声明、缺少必要的头文件导入等。
    • 作用域问题:尝试访问仅在另一个作用域中定义的变量或函数时,会发生作用域错误。
    • 链接错误:如果代码中存在对未定义或未实现的外部函数或变量的引用,进行完整编译过程时会被识别为链接错误。
    • 警告:警告不会阻止代码的编译,但它们指出了可能导致运行时错误的代码实践,如可能的变量未初始化、未使用的变量、潜在的类型转换问题等
    • 内存访问错误:会静态检测到潜在的内存访问问题,如数组越界访问、解引用空指针等,尽管许多此类错误需要运行时检查来发现。
    • 优化建议:提出代码优化的建议,以改善性能或减少内存消耗,虽然这通常不会影响编译过程的成功与否。
    • 标准遵从性:会检查代码是否遵循了选定的 C 语言标准(如 C99、C11 等),包括对废弃特性的使用警告等。
  • 支持文件输入和字符串输入代码

    • –file file_path 输入文件输入代码

    • –code “” 字符串输入代码

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      ./cust -c "$(cat <<EOF
      #include <iostream>
      #include <cstdarg>

      void print_values(int n, ...) {
      va_list vl;
      va_start(vl, n);
      for (int i = 0; i < n; i++) {
      int value = va_arg(vl, int);
      std::cout << "Value: " << value << "\\n";
      }
      va_end(vl);
      }
      int main() {
      print_values(3, 10, 20, 30);
      return 0;
      }
      EOF
      )"
  • 支持输出到 stdout 和文件

  • -o stdout | dst_file_path 输出定向到标准输出或目标文件中

体系架构

流程图

graph TB;
	符号表
	src[字符流]:::no_border
	an1[词法分析器]
	an2[语法分析]
	an3[语义分析]
	code_gen1[中间代码生成器]
	code_opt[语言无关代码优化器]
	code_gen2[代码生成器]
	code_gen3[机器相关代码优化器]
	dst[目标语言]:::no_border
	src --> an1 -->|符号流| an2 -->|语法树| an3 -->|语法树| code_gen1 -->|中间表示形式| code_opt -->|中间表示形式| code_gen2 -->|目标机器语言| code_gen3 --> dst
	
	
	classDef no_border fill:transparent, stroke:transparent ;
解析对象和流程
---
title: 解析对象和流程
---

graph TB;
	src[用户输入]:::no_border
	
    subgraph Cust[cust 程序]
        an1[获取用户输入 file is-ai-opt output]
        an2[检查C代码正确性]
        an3[语法、语义、词法分析]
        code_gen1[中间代码生成器]
        code_opt[中间代码优化器]
        code_gen2[Rust 代码生成器]
        code_gen3[Rust 代码优化器]
        code_opt2[ai 优化]
        dst[Rust 代码输出]:::no_border
	end
    src --> an1 -->|获取待解析的C代码| an2 -->|待解析的C代码| an3 -->|语法树 AST| code_gen1 -->|中间表示形式 IR| code_opt -->|中间表示形式 IR| code_gen2 -->|Rust 语言| code_gen3 --> dst
    an1 & an2 & an3 & code_gen1 & code_opt & code_gen2 & code_gen3 ---> code_opt2 ---> dst
	classDef no_border fill:transparent, stroke:transparent ;

时序图

sequenceDiagram
    participant UserInput as 用户输入
    participant CustProgram as cust 程序
    participant CCheck as 检查C代码正确性
    participant Analysis as 语法、语义、词法分析
    participant IRGen as 中间代码生成器
    participant IROpt as 中间代码优化器
    participant RustCodeGen as Rust 代码生成器
    participant RustOpt as Rust 代码优化器
    participant AIOpt as ai 优化
    participant RustOutput as Rust 代码输出

    UserInput->>CustProgram: 获取用户输入
    CustProgram->>CCheck: 获取待解析的C代码
    CCheck->>Analysis: 待解析的C代码
    Analysis->>IRGen: 语法树 AST
    IRGen->>IROpt: 中间表示形式 IR
    IROpt->>RustCodeGen: 中间表示形式 IR
    RustCodeGen->>RustOpt: Rust 语言
    RustOpt->>AIOpt: Rust 代码
    AIOpt->>RustOutput: 优化后的Rust代码

输入和输出

  • 字符输入

image-20240326225550130

  • 代码文件输入

image-20240326225753595

  • 输出
    • 代码检查
    • 转换代码
    • AI 优化代码

image-20240326225616707

image-20240326225824678

关键技术点

clang libclang llvm

Rust crate clang clang-sys syn

llvm IR

逻辑架构

  • 代码输入
  • clang-sys 词法、语法、语义解析
  • clang AST 建立
  • IR 结构生成器
  • Rust 翻译规则生成
  • Rust 代码生成
  • Rust 代码优化
  • AI 检查、优化

部署要求

llvm clang 库安装

1
2
3
# ubuntu22.04
sudo apt-get update
sudo apt-get install llvm clang

Rust cargo 基础开发环境、能访问外网拉取 crate。

如果使用 ai 优化功能,需要能连接通义千问。本项目代码中内置 api key

问题、解决思路

  • 入参 int n … 语法翻译问题
    • 通过 AST 中解析出参数中是否有此语法,如果有,则在 IR 中做出记录,在 IR to Rust 中将其转换为 Vec<T> , 并在之后的 Function body 逻辑处理中,将 C 中对 n 的处理,转换为 Rust 对 Vec n 的处理。在上下文中记录此函数声明和此参数上下文。
  • 获取 for 循环中的 condition 的 operator 思路
    • 计算左操作数的偏移量(left_offset
      • 首先,获取左操作数实体(entity.get_child(0)),假设为二元操作的第一个子实体。
      • 使用 .map 遍历左操作数的子实体(这里实际上只有一个),获取每个子实体的源代码范围(get_range()),然后对这个范围内的标记(tokenize())进行计数(.len()),以确定左操作数占用了多少个标记。
      • 通过 .fold 将这些标记数量累加起来,得到 left_offset,即左操作数结束的位置(以标记计数为单位)。
    • 获取整个二元操作的标记
      • 通过 entity.get_range().and_then(|r| Some(r.tokenize())) 获取表示整个二元操作的 Entity 的源代码范围,并将这个范围内的内容分割成标记。
    • 提取操作符
      • 使用左操作数的偏移量 left_offset 作为索引,从整个二元操作的标记列表中提取操作符。因为左操作数后面紧跟的标记应该就是操作符本身。
    • 返回操作符的拼写
      • 通过 get_spelling() 方法获取操作符标记的文本表示,然后将其作为 Some 值返回。

总结

产品

  1. 创新性结合: 利用编译原理和现有的AI技术的优势,提供一个高效且可靠的C/C++到Rust的代码转换工具。
  2. 高度复用设计: 通过先将C代码转换为中间表示(IR),然后再将IR转换为Rust代码的策略,增强了代码的可复用性,同时也支持将IR转换为其他目标语言。
  3. 硬件和平台无关: IR设计独立于任何特定的硬件或指令集,使得转换出来的Rust代码能够跨平台使用。
  4. 易于优化: IR层面的设计便于代码分析和优化,有助于生成性能更高、内存使用更优的Rust代码。同时后期迭代可以有多级的IR,做到职责单一、程序便于维护迭代。
  5. 支持广泛的错误排查和优化: 包括语法错误、类型错误、声明和定义错误、作用域问题、链接错误、内存访问错误等,以及提供代码优化建议。
  6. 灵活的输入输出: 支持文件输入和字符串输入,以及输出到标准输出或文件,提高了工具的使用灵活性。
  7. 开源许可: 采用GPL v3开源许可证,促进了社区的贡献和软件的持续改进。

致谢

我的演讲结束,谢谢大家,具体的实现可以看源码 和 演示视频


软件说明文档.md
https://abrance.github.io/2024/03/20/mdstorage/project/cToRust/软件说明文档/
Author
xiaoy
Posted on
March 20, 2024
Licensed under