4个版本 (稳定)

1.0.2 2023年3月20日
1.0.1 2023年3月19日
0.1.0 2023年1月28日

#275 in 编程语言

Download history 4/week @ 2024-03-29

每月75次下载

自定义许可证

330KB
8K SLoC

phoron_asm

github workflow crates.io docs.rs

本项目定义了Phoron,一个兼容JasminJVM指令集的汇编器。

关于规范,请参阅语法

设计

示例代码

对于Phoron的测试语法,请参阅设计文档

  $ cargo build --release 

构建

示例运行

.class public HelloWorld
.super java/lang/Object

.method public <init>()V
  aload_0 
  invokespecial java/lang/Object/<init>()V ; super ()
  return
.end method

.method public static main([Ljava/lang/String;)V
  .limit stack 2
  getstatic java/lang/System/out Ljava/io/PrintStream;
  ldc "Hello, world"
  invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
  return
.end method

对于示例源文件HelloWorld.pho

  $ cargo run --release -- -f samples/HelloWorld.pho

生成class文件

$ javap -v HelloWorld.class
Classfile /Users/z0ltan/dev/oyi-lang/phoron_asm/samples/HelloWorld.class
  Last modified 19-Mar-2023; size 389 bytes
  SHA-256 checksum 533a66c051831cba84a32b20d38c4bb20d68b78aabc137d7c7fb3cc864ff8bf9
  Compiled from "./samples/HelloWorld.pho"
public class HelloWorld
  minor version: 3
  major version: 45
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #4                          // HelloWorld
  super_class: #6                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 1
Constant pool:
   #1 = Utf8               SourceFile
   #2 = Utf8               ./samples/HelloWorld.pho
   #3 = Utf8               HelloWorld
   #4 = Class              #3             // HelloWorld
   #5 = Utf8               java/lang/Object
   #6 = Class              #5             // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = NameAndType        #7:#8          // "<init>":()V
  #11 = Methodref          #6.#10         // java/lang/Object."<init>":()V
  #12 = Utf8               main
  #13 = Utf8               ([Ljava/lang/String;)V
  #14 = Utf8               java/lang/System
  #15 = Class              #14            // java/lang/System
  #16 = Utf8               out
  #17 = Utf8               Ljava/io/PrintStream;
  #18 = NameAndType        #16:#17        // out:Ljava/io/PrintStream;
  #19 = Fieldref           #15.#18        // java/lang/System.out:Ljava/io/PrintStream;
  #20 = Utf8               Hello, world
  #21 = String             #20            // Hello, world
  #22 = Utf8               java/io/PrintStream
  #23 = Class              #22            // java/io/PrintStream
  #24 = Utf8               println
  #25 = Utf8               (Ljava/lang/String;)V
  #26 = NameAndType        #24:#25        // println:(Ljava/lang/String;)V
  #27 = Methodref          #23.#26        // java/io/PrintStream.println:(Ljava/lang/String;)V
{
  public HelloWorld();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #11                 // Method java/lang/Object."<init>":()V
         4: return

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #19                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #21                 // String Hello, world
         5: invokevirtual #27                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
}
SourceFile: "./samples/HelloWorld.pho"

进行合理性检查以确保生成的class文件有效

$ java -cp . HelloWorld
Hello, world

示例API使用

使用API的相同示例。

use std::{
    error::Error,
    fmt, fs,
    io::BufWriter,
    path::{Path, PathBuf},
};

use phoron_asm::{
    codegen::Codegen, cp_analyzer::ConstantPoolAnalyzer, lexer::Lexer, parser::Parser,
    sourcefile::SourceFile,
};

#[derive(Debug)]
pub struct RunError {
    message: String,
}

impl Error for RunError {}

impl fmt::Display for RunError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.message)
    }
}

fn process_file(src_file: &PathBuf) -> Result<(), Box<dyn std::error::Error>> {
    let outfile = src_file.with_extension("class");

    let source_file = SourceFile::new(src_file).map_err(|err| RunError {
        message: err.to_string(),
    })?;
    let mut parser = Parser::new(Lexer::new(&source_file));
    let ast = parser.parse().unwrap();

    if parser.errored() {
        return Err(Box::new(RunError {
            message: "errors encountered during parsing and typ-checking".into(),
        }));
    }

    let mut cp_analyzer = ConstantPoolAnalyzer::new();
    let cp = cp_analyzer.analyze(&ast).map_err(|err| RunError {
        message: err.to_string(),
    })?;

    let mut outfile_w = BufWriter::new(fs::File::create(&outfile)?);
    let mut codegen = Codegen::new(&mut outfile_w);
    codegen.gen_bytecode(&ast, &cp).map_err(|err| RunError {
        message: err.to_string(),
    })?;

    Ok(())
}

fn main() {
    let src_file = Path::new("./samples/").join("HelloWorld.pho");
    match process_file(&src_file) {
        Err(err) => eprintln!("{err}"),
        Ok(_) => println!("Class file generated"),
    }
}

运行

$ cargo run --release
Class file generated

$ javap -v samples/HelloWorld.class
Classfile /Users/z0ltan/dev/playground/phoron_asm_demo/samples/HelloWorld.class
  Last modified 19-Mar-2023; size 389 bytes
  SHA-256 checksum 533a66c051831cba84a32b20d38c4bb20d68b78aabc137d7c7fb3cc864ff8bf9
  Compiled from "./samples/HelloWorld.pho"
public class HelloWorld
  minor version: 3
  major version: 45
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #4                          // HelloWorld
  super_class: #6                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 1
Constant pool:
   #1 = Utf8               SourceFile
   #2 = Utf8               ./samples/HelloWorld.pho
   #3 = Utf8               HelloWorld
   #4 = Class              #3             // HelloWorld
   #5 = Utf8               java/lang/Object
   #6 = Class              #5             // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = NameAndType        #7:#8          // "<init>":()V
  #11 = Methodref          #6.#10         // java/lang/Object."<init>":()V
  #12 = Utf8               main
  #13 = Utf8               ([Ljava/lang/String;)V
  #14 = Utf8               java/lang/System
  #15 = Class              #14            // java/lang/System
  #16 = Utf8               out
  #17 = Utf8               Ljava/io/PrintStream;
  #18 = NameAndType        #16:#17        // out:Ljava/io/PrintStream;
  #19 = Fieldref           #15.#18        // java/lang/System.out:Ljava/io/PrintStream;
  #20 = Utf8               Hello, world
  #21 = String             #20            // Hello, world
  #22 = Utf8               java/io/PrintStream
  #23 = Class              #22            // java/io/PrintStream
  #24 = Utf8               println
  #25 = Utf8               (Ljava/lang/String;)V
  #26 = NameAndType        #24:#25        // println:(Ljava/lang/String;)V
  #27 = Methodref          #23.#26        // java/io/PrintStream.println:(Ljava/lang/String;)V
{
  public HelloWorld();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #11                 // Method java/lang/Object."<init>":()V
         4: return

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #19                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #21                 // String Hello, world
         5: invokevirtual #27                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
}
SourceFile: "./samples/HelloWorld.pho"

$ java -cp "./samples" HelloWorld
Hello, world

依赖

~150KB