├── .gitignore ├── .vscode └── settings.json ├── src ├── error_report.rs ├── parser │ ├── ty.rs │ ├── node.rs │ └── var_env.rs ├── main.rs ├── tokenizer │ ├── token.rs │ └── token_list.rs ├── codegen.rs ├── tokenizer.rs └── parser.rs ├── Makefile ├── Cargo.toml ├── .github └── workflows │ ├── cargo_test.yaml │ └── clippy.yaml ├── README.md ├── Cargo.lock ├── test.sh └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | tmp* 3 | *.un~ 4 | *.o 5 | *.s 6 | test.c -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[rust]": { 3 | "editor.formatOnSave": true 4 | }, 5 | } -------------------------------------------------------------------------------- /src/error_report.rs: -------------------------------------------------------------------------------- 1 | pub fn error_at(input: &str, pos: usize, msg: &str) { 2 | eprintln!("{}", input); 3 | eprintln!("{}^ {}", " ".repeat(pos), msg); 4 | } 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PHONY: test clean 2 | 3 | compiler-book-rs: ./target/debug/compiler-book-rs 4 | 5 | ./target/debug/compiler-book-rs: ./src/*.rs 6 | cargo build 7 | 8 | test: compiler-book-rs 9 | ./test.sh 10 | 11 | clean: 12 | cargo clean 13 | rm tmp* 14 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "compiler-book-rs" 4 | version = "0.1.0" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | anyhow = "1.0" 10 | itertools = "0.10.3" 11 | -------------------------------------------------------------------------------- /.github/workflows/cargo_test.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | branches: 4 | - main 5 | name: Cargo test 6 | jobs: 7 | cargo_test: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v1 11 | - uses: actions-rs/cargo@v1 12 | with: 13 | command: test 14 | -------------------------------------------------------------------------------- /.github/workflows/clippy.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | branches: 4 | - main 5 | name: Clippy check 6 | jobs: 7 | clippy_check: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v1 11 | - run: rustup component add clippy 12 | - uses: actions-rs/clippy-check@v1 13 | with: 14 | token: ${{ secrets.GITHUB_TOKEN }} 15 | args: --all-features 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # compiler-book-rs 2 | 3 | [『低レイヤを知りたい人のためのCコンパイラ作成入門』](https://www.sigbus.info/compilerbook) をM1 Mac上でRustで追ってみる 4 | 5 | # Sample 6 | 7 | ```c: sample.c 8 | int a; 9 | int *b; 10 | int c[10][10]; 11 | 12 | int main() 13 | { 14 | int d; 15 | a = 10; 16 | b = &d; 17 | *b = 10; 18 | int e[2][3]; 19 | e[1][2] = 2; 20 | c[9][9] = 10; 21 | // Line comment 22 | /* 23 | * Block comment 24 | */ 25 | /* Inline block comment */printf("hello, world\n");//Inline line comment 26 | return a + *b + c[9][9] + d + e[1][2]; 27 | } 28 | ``` 29 | 30 | ```shell 31 | $ cargo run -- sample.c > sample.s 32 | $ cc -o sample sample.s 33 | $ ./sample 34 | hello, world 35 | $ echo $? 36 | 42 37 | ``` 38 | -------------------------------------------------------------------------------- /src/parser/ty.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone, PartialEq, Eq, Debug)] 2 | pub enum Ty { 3 | Int, 4 | Char, 5 | Ptr(Box), 6 | Array(Box, i32), 7 | } 8 | 9 | impl Ty { 10 | pub fn size(&self) -> i32 { 11 | match self { 12 | Ty::Char => 1, 13 | Ty::Int => 4, 14 | Ty::Ptr(_) => 8, 15 | Ty::Array(ty, len) => { 16 | let ty_size = ty.size(); 17 | ty_size * len 18 | } 19 | } 20 | } 21 | 22 | pub fn is_reference_type(&self) -> bool { 23 | matches!(self, Ty::Ptr(_) | Ty::Array(..)) 24 | } 25 | 26 | pub fn base_ty(&self) -> Ty { 27 | match self { 28 | Ty::Ptr(ty) => *ty.clone(), 29 | Ty::Array(ty, _) => *ty.clone(), 30 | _ => panic!("{:?} is not refrence type", self), 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "anyhow" 7 | version = "1.0.55" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd" 10 | 11 | [[package]] 12 | name = "compiler-book-rs" 13 | version = "0.1.0" 14 | dependencies = [ 15 | "anyhow", 16 | "itertools", 17 | ] 18 | 19 | [[package]] 20 | name = "either" 21 | version = "1.6.1" 22 | source = "registry+https://github.com/rust-lang/crates.io-index" 23 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 24 | 25 | [[package]] 26 | name = "itertools" 27 | version = "0.10.3" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" 30 | dependencies = [ 31 | "either", 32 | ] 33 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod codegen; 2 | mod error_report; 3 | mod parser; 4 | mod tokenizer; 5 | 6 | use crate::{parser::Parser, tokenizer::Tokenizer}; 7 | use std::{env, io::Read, path::PathBuf}; 8 | 9 | fn main() { 10 | let args = env::args().collect::>(); 11 | if args.len() != 2 { 12 | println!("Usage: {} ", args[0]); 13 | return; 14 | } 15 | 16 | let program = read_program(args[1].clone()); 17 | let token_list = Tokenizer::new(&program).tokenize(); 18 | let (program_node, string_literals) = Parser::new(token_list).program(); 19 | let code_generator = codegen::CodeGenerator::new(program_node, string_literals); 20 | code_generator.generate(); 21 | } 22 | 23 | fn read_program>(path: P) -> String { 24 | let mut file = std::fs::File::open(path.into()).unwrap(); 25 | let mut contents = String::new(); 26 | file.read_to_string(&mut contents).unwrap(); 27 | if !contents.ends_with("\n") { 28 | contents.push('\n'); 29 | } 30 | contents 31 | } 32 | -------------------------------------------------------------------------------- /src/parser/node.rs: -------------------------------------------------------------------------------- 1 | use super::ty::Ty; 2 | 3 | #[derive(PartialEq, Eq, Debug)] 4 | 5 | pub enum BinOpType { 6 | Add, 7 | Sub, 8 | Mul, 9 | Div, 10 | Equal, 11 | NotEqual, 12 | LessThan, 13 | LessThanOrEqual, 14 | } 15 | 16 | #[derive(PartialEq, Eq, Debug)] 17 | pub enum Ast { 18 | BinOp(BinOpType, Box, Box), 19 | Assign(Box, Box), 20 | LocalVar { 21 | name: String, 22 | offset: i32, 23 | }, 24 | GlobalVar { 25 | name: String, 26 | }, 27 | StringLiteral { 28 | label: String, 29 | }, 30 | Num(i32), 31 | Return(Box), 32 | If(Box, Box, Option>), 33 | While(Box, Box), 34 | For( 35 | Option>, 36 | Option>, 37 | Option>, 38 | Box, 39 | ), 40 | Block(Vec), 41 | Funcall(String, Vec), 42 | Fundef { 43 | name: String, 44 | args: Vec, 45 | body: Vec, 46 | stack_size: i32, 47 | }, 48 | Addr(Box), 49 | Deref(Box), 50 | LocalVarDef(String, Ty), 51 | GlobalVarDef(String, Ty), 52 | } 53 | 54 | #[derive(PartialEq, Eq, Debug)] 55 | pub struct Node { 56 | pub ast: Ast, 57 | pub ty: Option, 58 | } 59 | 60 | impl Node { 61 | pub fn new(ast: Ast, ty: Option) -> Self { 62 | Self { ast, ty } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/tokenizer/token.rs: -------------------------------------------------------------------------------- 1 | #[derive(PartialEq, Eq, Debug, Clone)] 2 | pub enum TokenKind { 3 | Plus, 4 | Minus, 5 | Star, 6 | Div, 7 | Num, 8 | Ident, 9 | LParen, 10 | RParen, 11 | LBrace, 12 | RBrace, 13 | LBracket, 14 | RBracket, 15 | LessThan, 16 | LessThanOrEqual, 17 | GreaterThan, 18 | GreaterThanOrEqual, 19 | Assign, 20 | Equal, 21 | NotEqual, 22 | Semicolon, 23 | Return, 24 | If, 25 | Else, 26 | While, 27 | For, 28 | Comma, 29 | Ampersand, 30 | SizeOf, 31 | String, 32 | // Type like 33 | Int, 34 | Char, 35 | } 36 | 37 | #[derive(PartialEq, Eq, Debug, Clone)] 38 | pub struct Token { 39 | pub position: usize, 40 | pub kind: TokenKind, 41 | pub num: Option, // Number 42 | pub str: Option, // Identifier 43 | } 44 | 45 | impl Token { 46 | pub fn new_syntax_item(position: usize, kind: TokenKind) -> Self { 47 | Self { 48 | position, 49 | kind, 50 | num: None, 51 | str: None, 52 | } 53 | } 54 | 55 | pub fn new_num(position: usize, num: i32) -> Self { 56 | Self { 57 | position, 58 | kind: TokenKind::Num, 59 | num: Some(num), 60 | str: None, 61 | } 62 | } 63 | 64 | pub fn new_ident(position: usize, str: &str) -> Self { 65 | Self { 66 | position, 67 | kind: TokenKind::Ident, 68 | num: None, 69 | str: Some(str.to_string()), 70 | } 71 | } 72 | 73 | pub fn new_str(position: usize, str: String) -> Self { 74 | Self { 75 | position, 76 | kind: TokenKind::String, 77 | num: None, 78 | str: Some(str), 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/tokenizer/token_list.rs: -------------------------------------------------------------------------------- 1 | use std::process::exit; 2 | 3 | use crate::error_report::error_at; 4 | 5 | use super::token::{Token, TokenKind}; 6 | 7 | #[derive(Debug)] 8 | pub struct TokenList<'a> { 9 | original_input: &'a str, 10 | tokens: Vec, 11 | pos: usize, 12 | } 13 | 14 | impl<'a> TokenList<'a> { 15 | pub fn new(original_input: &'a str, tokens: Vec) -> Self { 16 | Self { 17 | original_input, 18 | tokens, 19 | pos: 0, 20 | } 21 | } 22 | 23 | pub fn next(&mut self) -> Option { 24 | if self.pos >= self.tokens.len() { 25 | None 26 | } else { 27 | let token = self.tokens[self.pos].clone(); 28 | self.advance(); 29 | Some(token) 30 | } 31 | } 32 | 33 | pub fn at_end(&self) -> bool { 34 | self.pos >= self.tokens.len() 35 | } 36 | 37 | pub fn peek(&self) -> Option { 38 | if self.pos < self.tokens.len() { 39 | Some(self.tokens[self.pos].clone()) 40 | } else { 41 | None 42 | } 43 | } 44 | 45 | pub fn try_consume(&mut self, kind: &TokenKind) -> Option { 46 | let next = self.peek(); 47 | if let Some(next) = next { 48 | if next.kind == *kind { 49 | self.next() 50 | } else { 51 | None 52 | } 53 | } else { 54 | None 55 | } 56 | } 57 | 58 | pub fn expect_kind(&mut self, kind: &TokenKind) -> Token { 59 | let next = self.peek(); 60 | if let Some(next) = next { 61 | if next.kind == *kind { 62 | self.advance(); 63 | next 64 | } else { 65 | self.exit_with_unexpected_token(next.position, &format!("Expected {:?}", kind)); 66 | } 67 | } else { 68 | self.exit_with_unexpected_eof(&format!("Expected {:?}", kind)); 69 | } 70 | } 71 | 72 | pub fn expect_num(&mut self) -> i32 { 73 | let next_token = self.peek(); 74 | match next_token { 75 | Some(token) => { 76 | if token.kind == TokenKind::Num { 77 | self.advance(); 78 | token.num.unwrap() 79 | } else { 80 | self.exit_with_unexpected_token(token.position, "Expected number"); 81 | } 82 | } 83 | None => { 84 | self.exit_with_unexpected_eof("Expected number"); 85 | } 86 | } 87 | } 88 | 89 | fn exit_with_unexpected_token(&self, position: usize, additional_message: &str) -> ! { 90 | if additional_message.is_empty() { 91 | error_at(self.original_input, position, "Unexpected Token"); 92 | } else { 93 | error_at( 94 | self.original_input, 95 | position, 96 | &format!("Unexpected Token, {}", additional_message), 97 | ); 98 | } 99 | exit(1) 100 | } 101 | 102 | fn exit_with_unexpected_eof(&self, additional_message: &str) -> ! { 103 | if additional_message.is_empty() { 104 | error_at( 105 | self.original_input, 106 | self.original_input.len(), 107 | "Unexpected EOF", 108 | ); 109 | } else { 110 | error_at( 111 | self.original_input, 112 | self.original_input.len(), 113 | &format!("Unexpected EOF, {}", additional_message), 114 | ); 115 | } 116 | exit(1) 117 | } 118 | 119 | fn advance(&mut self) { 120 | self.pos += 1; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/parser/var_env.rs: -------------------------------------------------------------------------------- 1 | use super::ty::Ty; 2 | use std::collections::HashMap; 3 | 4 | const STACK_ALIGNMENT: i32 = 16; 5 | 6 | #[derive(PartialEq, Eq, Debug, Clone)] 7 | pub struct LocalVarInfo { 8 | pub ty: Ty, 9 | pub offset: i32, 10 | } 11 | 12 | #[derive(PartialEq, Eq, Debug, Clone)] 13 | pub struct GlobalVarInfo { 14 | pub ty: Ty, 15 | pub label: String, 16 | } 17 | 18 | #[derive(PartialEq, Eq, Debug, Clone)] 19 | pub struct StringLiteralEntry { 20 | pub contents: String, 21 | pub label: String, 22 | } 23 | 24 | #[derive(PartialEq, Eq, Debug, Clone)] 25 | pub enum VarInfo { 26 | Local(LocalVarInfo), 27 | Global(GlobalVarInfo), 28 | } 29 | 30 | #[derive(Clone)] 31 | pub struct VarEnvironment { 32 | stack_offset: i32, 33 | local_variables: HashMap, 34 | global_variables: HashMap, 35 | pub string_literals: Vec, 36 | } 37 | 38 | impl VarEnvironment { 39 | pub fn new() -> Self { 40 | Self { 41 | stack_offset: 16, 42 | local_variables: HashMap::new(), 43 | global_variables: HashMap::new(), 44 | string_literals: vec![], 45 | } 46 | } 47 | 48 | // スタックのアラインメントに現在のoffsetをアラインした数を返す 49 | // たとえば5なら16, 16なら16, 17なら32 50 | pub fn stack_size(&self) -> i32 { 51 | (self.stack_offset + STACK_ALIGNMENT - 1) / STACK_ALIGNMENT * STACK_ALIGNMENT 52 | } 53 | 54 | pub fn add_local_var(&mut self, name: &str, ty: Ty) -> LocalVarInfo { 55 | if let Some(var_info) = self.local_variables.get(name) { 56 | var_info.clone() 57 | } else { 58 | let size = ty.size(); 59 | self.stack_offset += size; 60 | let var_info = LocalVarInfo { 61 | ty, 62 | offset: self.stack_offset, 63 | }; 64 | self.local_variables 65 | .insert(name.to_string(), var_info.clone()); 66 | var_info 67 | } 68 | } 69 | 70 | pub fn add_global_var(&mut self, name: &str, ty: Ty) -> GlobalVarInfo { 71 | if let Some(var_info) = self.global_variables.get(name) { 72 | var_info.clone() 73 | } else { 74 | let var_info = GlobalVarInfo { 75 | ty, 76 | label: name.to_owned(), 77 | }; 78 | self.global_variables 79 | .insert(name.to_string(), var_info.clone()); 80 | var_info 81 | } 82 | } 83 | 84 | pub fn add_string_literal(&mut self, str: &str) -> String { 85 | let label = format!("l_.str.{}", self.string_literals.len()); 86 | self.string_literals.push(StringLiteralEntry { 87 | contents: str.to_owned(), 88 | label: label.clone(), 89 | }); 90 | 91 | label 92 | } 93 | 94 | // 変数の名前を解決する 95 | // ローカル変数は同名のグローバル変数をシャドーイングするので、まずはローカルの変数を探す 96 | pub fn resolve(&self, name: &str) -> Option { 97 | if let Some(local_var_info) = self.local_variables.get(name) { 98 | Some(VarInfo::Local(local_var_info.clone())) 99 | } else { 100 | self.global_variables 101 | .get(name) 102 | .map(|global_var_info| VarInfo::Global(global_var_info.clone())) 103 | } 104 | } 105 | 106 | pub fn clear_local_variables(&mut self) { 107 | self.local_variables.clear() 108 | } 109 | } 110 | 111 | #[cfg(test)] 112 | mod test { 113 | use super::{GlobalVarInfo, LocalVarInfo, VarEnvironment, VarInfo}; 114 | use crate::parser::Ty; 115 | 116 | #[test] 117 | fn add_local_var() { 118 | let mut var_env = VarEnvironment::new(); 119 | assert_eq!( 120 | var_env.add_local_var("x", Ty::Int), 121 | LocalVarInfo { 122 | ty: Ty::Int, 123 | offset: 20, 124 | } 125 | ); 126 | } 127 | 128 | #[test] 129 | fn add_global_var() { 130 | let mut var_env = VarEnvironment::new(); 131 | assert_eq!( 132 | var_env.add_global_var("x", Ty::Int), 133 | GlobalVarInfo { 134 | ty: Ty::Int, 135 | label: "x".to_owned(), 136 | } 137 | ); 138 | } 139 | 140 | #[test] 141 | fn resolve_local_var() { 142 | let mut var_env = VarEnvironment::new(); 143 | var_env.add_local_var("x", Ty::Int); 144 | assert_eq!( 145 | var_env.resolve("x"), 146 | Some(VarInfo::Local(LocalVarInfo { 147 | ty: Ty::Int, 148 | offset: 20, 149 | })) 150 | ); 151 | } 152 | 153 | #[test] 154 | fn resolve_global_var() { 155 | let mut var_env = VarEnvironment::new(); 156 | var_env.add_global_var("x", Ty::Int); 157 | assert_eq!( 158 | var_env.resolve("x"), 159 | Some(VarInfo::Global(GlobalVarInfo { 160 | ty: Ty::Int, 161 | label: "x".to_owned(), 162 | })) 163 | ); 164 | } 165 | 166 | #[test] 167 | fn lobal_var_shadowing_global_var() { 168 | let mut var_env = VarEnvironment::new(); 169 | var_env.add_global_var("x", Ty::Int); 170 | var_env.add_local_var("x", Ty::Int); 171 | assert_eq!( 172 | var_env.resolve("x"), 173 | Some(VarInfo::Local(LocalVarInfo { 174 | ty: Ty::Int, 175 | offset: 20, 176 | })) 177 | ); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cat < 4 | #include 5 | int add(int x, int y) { return x+y; } 6 | void alloc4(int **p, int a, int b, int c, int d) { 7 | int *int_ptr = (int *)malloc(sizeof(int) * 4); 8 | int_ptr[0] = a; 9 | int_ptr[1] = b; 10 | int_ptr[2] = c; 11 | int_ptr[3] = d; 12 | 13 | *p = int_ptr; 14 | } 15 | EOF 16 | 17 | assert() { 18 | expected="$1" 19 | input="$2" 20 | 21 | echo "$input" > tmp.c 22 | RUST_BACKTRACE=1 cargo run -- tmp.c > tmp.s 23 | cc -c tmp.s 24 | cc -o tmp tmp.o tmp2.o 25 | ./tmp 26 | actual="$?" 27 | 28 | if [ "$actual" = "$expected" ]; then 29 | echo "$input => $actual" 30 | else 31 | echo "$input => $expected expected, but got $actual" 32 | exit 1 33 | fi 34 | } 35 | 36 | # 値を返すだけ 37 | assert 42 'int main() { return 42; }' 38 | 39 | # 四則演算 40 | assert 47 'int main() { return 5+6*7; }' 41 | assert 15 'int main() { return 5*(9-6); }' 42 | assert 4 'int main() { return (3+5)/2; }' 43 | assert 10 'int main() { return -10+20; }' 44 | 45 | # 比較演算 46 | assert 1 'int main() { return 2<3; }' 47 | assert 1 'int main() { return 2<=2; }' 48 | assert 1 'int main() { return 3>2; }' 49 | assert 1 'int main() { return 2>=2; }' 50 | assert 1 'int main() { return 2==2; }' 51 | assert 1 'int main() { return 3!=2; }' 52 | 53 | assert 0 'int main() { return 3<2; }' 54 | assert 0 'int main() { return 3<=2; }' 55 | assert 0 'int main() { return 2>3; }' 56 | assert 0 'int main() { return 2>=3; }' 57 | assert 0 'int main() { return 2==3; }' 58 | assert 0 'int main() { return 2!=2; }' 59 | 60 | # 1文字変数 61 | assert 42 'int main() { int a; a = 42; return a; }' 62 | assert 21 'int main() { int a; int b; int c; a = 5; b = 20; c = 4; return a + b - c; }' 63 | 64 | # 複数文字変数 65 | assert 42 'int main() { int foo; foo = 42; return foo; }' 66 | assert 21 'int main() { int foo; int bar; int baz; foo = 5; bar = 20; baz = 4; return foo + bar - baz; }' 67 | 68 | # return 69 | assert 42 'int main() { int foo; foo = 42; return foo; }' 70 | assert 5 'int main() { int a; int b; a = 5; return a; b = 20; }' 71 | 72 | # if else 73 | assert 42 'int main() { int a; a = 10; if (a == 10) return 42; }' 74 | assert 42 'int main() { int a; a = 1; if (a != 10) return 42; return 24; }' 75 | assert 42 'int main() { int a; a = 10; if (a == 10) return 42; else return 24; }' 76 | assert 24 'int main() { int a; a = 10; if (a != 10) return 42; else return 24; }' 77 | 78 | # while 79 | assert 10 'int main() { int a; a = 0; while (a != 10) a = a + 1; return a; }' 80 | assert 1 'int main() { int a; a = 0; while (a == 0) a = a + 1; return a; }' 81 | 82 | # for 83 | assert 10 'int main() { int a; a = 0; for (a = 0; a < 10; a = a + 1) 42; return a; }' 84 | assert 10 'int main() { int a; a = 0; for (; a < 10; a = a + 1) 42; return a; }' 85 | 86 | # block 87 | assert 30 'int main() { int a; int b; int c; a = 0; b = 0; c = 0; if (a == 0) { b = 10; c = 20; } return b + c; }' 88 | assert 30 'int main() { int a; int b; int c; a = 0; b = 0; c = 0; if (a != 0) {} else { b = 10; c = 20; } return b + c; }' 89 | assert 10 'int main() { int a; int b; a = 0; b = 0; for (a = 0; a < 10;) { a = a + 1; b = b + 1; } return b; }' 90 | 91 | # funcall 92 | assert 3 'int main() { int a; int b; int c; a = 1; b = 2; c = add(a, b); return c; }' 93 | assert 10 'int main() { int c; c = add(add(1, 2), add(3, 4)); return c; }' 94 | 95 | # fndef 96 | assert 42 'int foo() { return 42; } int main() { return foo(); }' 97 | assert 24 'int fact(int a) { if (a == 0) { return 1; } else { return a * fact(a - 1); } } int main() { return fact(4); }' 98 | assert 55 'int fib(int a) { if (a == 0) { return 0; } else if (a == 1) { return 1; } else { return fib(a - 1) + fib(a - 2); } } int main() { return fib(10); }' 99 | assert 42 'int foo(int a) { int b; b = a + 1; return b; } int main() { return foo(41); }' 100 | 101 | # addr 102 | assert 3 'int main() { int x; int* y; x = 3; y = &x; return *y; }' 103 | 104 | # int ptr 105 | assert 3 'int main() { int x; int *y; y = &x; *y = 3; return x; }' 106 | 107 | # pointer arithmetic 108 | assert 4 'int main() { int *p; alloc4(&p, 1, 2, 4, 8); int *q; q = p + 2; return *q; }' 109 | assert 8 'int main() { int *p; alloc4(&p, 1, 2, 4, 8); int *q; q = p + 3; return *q; }' 110 | assert 2 'int main() { int *p; alloc4(&p, 1, 2, 4, 8); int *q; q = p + 2; q = q - 1; return *q; }' 111 | 112 | # sizeof 113 | assert 4 'int main() { int x; x = sizeof(x); return x; }' 114 | assert 4 'int main() { int x; x = sizeof x; return x; }' 115 | assert 8 'int main() { int x; int *y; x = sizeof(y); return x; }' 116 | assert 8 'int main() { int x; int *y; x = sizeof y ; return x; }' 117 | 118 | # array var 119 | assert 3 'int main() { int x[3][3]; int y; y = 3; return y; }' 120 | assert 3 'int main() { int a[2]; *a = 1; *(a + 1) = 2; int *p; p = a; return *p + *(p + 1); }' 121 | assert 3 'int main() { int x[3]; *x=3; *(x+1)=4; *(x+2)=5; return *x; }' 122 | assert 4 'int main() { int x[3]; *x=3; *(x+1)=4; *(x+2)=5; return *(x+1); }' 123 | assert 5 'int main() { int x[3]; *x=3; *(x+1)=4; *(x+2)=5; return *(x+2); }' 124 | 125 | # multi dimension array 126 | assert 0 'int main() { int x[2][3]; int *y; y=&x; *y=0; return **x; }' 127 | assert 1 'int main() { int x[2][3]; int *y; y=&x; *(y+1)=1; return *(*x+1); }' 128 | assert 2 'int main() { int x[2][3]; int *y; y=&x; *(y+2)=2; return *(*x+2); }' 129 | assert 3 'int main() { int x[2][3]; int *y; y=&x; *(y+3)=3; return **(x+1); }' 130 | assert 4 'int main() { int x[2][3]; int *y; y=&x; *(y+4)=4; return *(*(x+1)+1); }' 131 | assert 5 'int main() { int x[2][3]; int *y; y=&x; *(y+5)=5; return *(*(x+1)+2); }' 132 | 133 | # array subscript 134 | assert 1 'int main() { int x[3]; x[0] = 1; x[1] = 2; x[2] = 4; return x[0]; }' 135 | assert 2 'int main() { int x[3]; x[0] = 1; x[1] = 2; x[2] = 4; return x[1]; }' 136 | assert 4 'int main() { int x[3]; x[0] = 1; x[1] = 2; x[2] = 4; return x[2]; }' 137 | assert 5 'int main() { int x[2][3]; x[1][2] = 5; return x[1][2]; }' 138 | 139 | # global var 140 | assert 42 'int foo; int main() { foo = 42; return foo; }' 141 | assert 42 'int *y; int main() { int x; y = &x; *y = 42; return x; }' 142 | assert 42 'int x[2][3]; int main() { x[1][2] = 42; return x[1][2]; }' 143 | assert 42 'int x[2][3]; int main() { x[0][0] = 42; return **x; }' 144 | 145 | # char 146 | assert 3 'int main() { char x[3]; x[0] = -1; x[1] = -2; int y; y = 4; return x[0] + y; }' 147 | 148 | # string 149 | assert 42 'int main() { char *c; c = "hello, world\n"; printf(c); return 42; }' 150 | assert 42 'int main() { printf("hello, world\n"); return 42; }' 151 | 152 | echo OK -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2022 Pocket7878 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/codegen.rs: -------------------------------------------------------------------------------- 1 | use crate::parser::{Ast, BinOpType, Node, StringLiteralEntry, Ty}; 2 | 3 | const FRAME_POINTER_REGISTER: &str = "x29"; 4 | const LINK_REGISTER: &str = "x30"; 5 | const STACK_ALIGNMENT: i32 = 16; 6 | 7 | pub struct CodeGenerator { 8 | program: Vec, 9 | string_literal_entries: Vec, 10 | } 11 | 12 | impl CodeGenerator { 13 | pub fn new(program: Vec, string_literal_entries: Vec) -> Self { 14 | Self { 15 | program, 16 | string_literal_entries, 17 | } 18 | } 19 | 20 | pub fn generate(&self) { 21 | println!("\t.section __TEXT,__text,regular,pure_instructions"); 22 | // プログラム中でユニークなラベルを生成するため 23 | let mut label_index = 0; 24 | for stmt in self.program.iter() { 25 | match stmt { 26 | Node { 27 | ast: Ast::Fundef { name, .. }, 28 | .. 29 | } => { 30 | self.gen(stmt, &mut label_index, Some(name)); 31 | } 32 | Node { 33 | ast: Ast::GlobalVarDef(name, ty), 34 | .. 35 | } => { 36 | println!(".comm _{},{}", name, ty.size()); 37 | } 38 | _ => { 39 | panic!("Unsupported toplevel node: {:?}", stmt); 40 | } 41 | } 42 | } 43 | 44 | if self.string_literal_entries.len() > 0 { 45 | println!("\t.section __TEXT,__cstring,cstring_literals"); 46 | for st_ent in self.string_literal_entries.iter() { 47 | println!("{}:", st_ent.label); 48 | println!("\t.asciz \"{}\"", st_ent.contents); 49 | } 50 | } 51 | } 52 | 53 | fn gen(&self, node: &Node, label_index: &mut i32, current_fn_name: Option<&str>) { 54 | self.generate_comment(&format!("Compiling: {:?}", node)); 55 | match &node.ast { 56 | Ast::Num(n) => { 57 | self.generate_comment(&format!("num: {}", n)); 58 | println!("\tmov x2, #{}", n); 59 | self.generate_push_register_to_stack("x2"); 60 | } 61 | Ast::LocalVarDef(_, _) => {} 62 | Ast::GlobalVarDef(..) => {} 63 | Ast::LocalVar { name, offset, .. } => { 64 | self.generate_comment(&format!("local var {} at {}", name, offset)); 65 | 66 | self.generate_comment("\t local var push address to stack"); 67 | self.generate_var(node); 68 | 69 | self.generate_comment("\t local var pop address from stack"); 70 | self.generate_pop_register_from_stack("x0"); 71 | 72 | self.generate_comment("\t local var read address content to register"); 73 | self.load(&node.ty); 74 | 75 | self.generate_comment("\t local var push value to stack"); 76 | self.generate_push_register_to_stack("x0"); 77 | } 78 | Ast::GlobalVar { name } => { 79 | self.generate_comment(&format!("global var {}", name)); 80 | 81 | self.generate_comment("\t global var push address to stack"); 82 | self.generate_var(node); 83 | 84 | self.generate_comment("\t global var pop address from stack"); 85 | self.generate_pop_register_from_stack("x0"); 86 | 87 | self.generate_comment("\t global var read address content to register"); 88 | self.load(&node.ty); 89 | 90 | self.generate_comment("\t global var push value to stack"); 91 | self.generate_push_register_to_stack("x0"); 92 | } 93 | Ast::StringLiteral { label } => { 94 | self.generate_comment(&format!("string literal with label: {}", label)); 95 | 96 | self.generate_comment("\t string literal var push address to stack"); 97 | println!("\tadrp x0, {}@PAGE", label); 98 | println!("\tadd x0, x0, {}@PAGEOFF", label); 99 | 100 | self.generate_comment("\t string literal read address content to register"); 101 | self.load(&node.ty); 102 | 103 | self.generate_comment("\t global var push value to stack"); 104 | self.generate_push_register_to_stack("x0"); 105 | } 106 | Ast::Addr(base_node) => { 107 | self.generate_var(base_node); 108 | } 109 | Ast::Deref(base_node) => { 110 | self.gen(base_node, label_index, current_fn_name); 111 | self.generate_pop_register_from_stack("x0"); 112 | self.load(&node.ty); 113 | self.generate_push_register_to_stack("x0"); 114 | } 115 | Ast::Assign(lhs, rhs) => { 116 | self.generate_comment("assign"); 117 | 118 | self.generate_comment("\tassign push lhs(address)"); 119 | if let Node { 120 | ast: Ast::Deref(derefed_lhs), 121 | .. 122 | } = &**lhs 123 | { 124 | self.gen(derefed_lhs, label_index, current_fn_name); 125 | } else { 126 | self.generate_var(lhs.as_ref()); 127 | } 128 | 129 | self.generate_comment("\tassign push rhs(value)"); 130 | self.gen(rhs.as_ref(), label_index, current_fn_name); 131 | 132 | self.generate_comment("\tassign pop value and address"); 133 | self.generate_pop_register_from_stack("x1"); 134 | self.generate_pop_register_from_stack("x0"); 135 | 136 | self.generate_comment("\tassign store values to address"); 137 | self.store(&rhs.as_ref().ty); 138 | 139 | // Cでは代入式は代入された値を返す 140 | self.generate_comment("\tassign push assigned value to stack"); 141 | self.generate_push_register_to_stack("x1"); 142 | } 143 | Ast::If(condition, then_body, else_body) => { 144 | self.generate_comment("if"); 145 | self.generate_comment("\tif condition"); 146 | self.gen(condition.as_ref(), label_index, current_fn_name); 147 | self.generate_pop_register_from_stack("x0"); 148 | println!("\tcmp x0, #0"); 149 | 150 | let idx = self.increment_label_index(label_index); 151 | if let Some(else_body) = &else_body { 152 | println!("\tb.eq .Lelse{}", idx); 153 | self.generate_comment("\tif then-body"); 154 | self.gen(then_body.as_ref(), label_index, current_fn_name); 155 | println!("\tb .Lend{}", idx); 156 | println!(".Lelse{}:", idx); 157 | self.generate_comment("\tif then-else-body"); 158 | self.gen(else_body, label_index, current_fn_name); 159 | } else { 160 | println!("\tb.eq .Lend{}", idx); 161 | self.gen(then_body.as_ref(), label_index, current_fn_name); 162 | } 163 | 164 | println!(".Lend{}:", idx); 165 | } 166 | Ast::While(condition, body) => { 167 | let idx = self.increment_label_index(label_index); 168 | println!(".Lbegin{}:", idx); 169 | self.gen(condition.as_ref(), label_index, current_fn_name); 170 | self.generate_pop_register_from_stack("x0"); 171 | println!("\tcmp x0, #0"); 172 | println!("\tb.eq .Lend{}", idx); 173 | self.gen(body.as_ref(), label_index, current_fn_name); 174 | println!("\tb .Lbegin{}", idx); 175 | println!(".Lend{}:", idx); 176 | } 177 | Ast::For(init, check, update, body) => { 178 | let idx = self.increment_label_index(label_index); 179 | if let Some(init) = init { 180 | self.gen(init.as_ref(), label_index, current_fn_name); 181 | } 182 | println!(".Lbegin{}:", idx); 183 | if let Some(check) = check { 184 | self.gen(check.as_ref(), label_index, current_fn_name); 185 | } else { 186 | // checkがない場合は常にtrueにする 187 | self.gen( 188 | &Node::new(Ast::Num(1), Some(Ty::Int)), 189 | label_index, 190 | current_fn_name, 191 | ); 192 | } 193 | self.generate_pop_register_from_stack("x0"); 194 | println!("\tcmp x0, #0"); 195 | println!("\tb.eq .Lend{}", idx); 196 | self.gen(body.as_ref(), label_index, current_fn_name); 197 | if let Some(update) = update { 198 | self.gen(update.as_ref(), label_index, current_fn_name); 199 | } 200 | println!("\tb .Lbegin{}", idx); 201 | println!(".Lend{}:", idx); 202 | } 203 | Ast::Block(stmts) => { 204 | for s in stmts { 205 | self.gen(s, label_index, current_fn_name); 206 | self.generate_pop_register_from_stack("x0"); 207 | } 208 | } 209 | Ast::Funcall(name, args) => { 210 | for a in args { 211 | self.gen(a, label_index, current_fn_name); 212 | } 213 | for i in (0..args.len()).rev() { 214 | self.generate_pop_register_from_stack(&format!("x{}", i)); 215 | } 216 | println!("\tbl _{}", name); 217 | // 関数の戻り値はx0に入っている 218 | self.generate_push_register_to_stack("x0"); 219 | } 220 | Ast::Return(value) => { 221 | self.generate_comment("return"); 222 | self.gen(value.as_ref(), label_index, current_fn_name); 223 | self.generate_pop_register_from_stack("x0"); 224 | println!("\tb .L.return_{}", current_fn_name.unwrap()); 225 | } 226 | Ast::Fundef { 227 | name, 228 | args, 229 | body, 230 | stack_size, 231 | } => { 232 | println!("\t.globl _{}", name); 233 | println!("\t.p2align 2"); 234 | println!("_{}:", name); 235 | self.generate_comment("Store FP & LR to stack"); 236 | println!( 237 | "\tstp {}, {}, [sp, #-16]!", 238 | FRAME_POINTER_REGISTER, LINK_REGISTER 239 | ); 240 | self.generate_comment("Update FP"); 241 | println!("\tmov {}, sp", FRAME_POINTER_REGISTER); 242 | self.generate_comment("Allocate stack space for local variables & arguments"); 243 | println!("\tsub sp, sp, #{}", stack_size); 244 | self.generate_comment("Copy arguments into stack"); 245 | for arg in args.iter().enumerate() { 246 | if let Ast::LocalVar { offset, .. } = arg.1.ast { 247 | println!( 248 | "\tstur x{}, [{}, #-{}]", 249 | arg.0, FRAME_POINTER_REGISTER, offset, 250 | ); 251 | } else { 252 | panic!("unexpected function arg ast: {:?}", arg.1.ast); 253 | } 254 | } 255 | for s in body { 256 | self.gen(s, label_index, Some(name)); 257 | } 258 | println!(".L.return_{}:", name); 259 | self.generate_comment("Restore FP & LR from stack"); 260 | println!("\tmov sp, {}", FRAME_POINTER_REGISTER); 261 | println!( 262 | "\tldp {}, {}, [sp], #16", 263 | FRAME_POINTER_REGISTER, LINK_REGISTER 264 | ); 265 | println!("\tret") 266 | } 267 | Ast::BinOp(op, lhs, rhs) => { 268 | self.gen(lhs.as_ref(), label_index, current_fn_name); 269 | self.gen(rhs.as_ref(), label_index, current_fn_name); 270 | self.generate_pop_register_from_stack("x1"); 271 | self.generate_pop_register_from_stack("x0"); 272 | 273 | match *op { 274 | BinOpType::Add => println!("\tadd x0, x0, x1"), 275 | BinOpType::Sub => println!("\tsub x0, x0, x1"), 276 | BinOpType::Mul => println!("\tmul x0, x0, x1"), 277 | BinOpType::Div => println!("\tsdiv x0, x0, x1"), 278 | BinOpType::Equal => { 279 | println!("\tcmp x0, x1"); 280 | println!("\tcset x0, EQ"); 281 | } 282 | BinOpType::NotEqual => { 283 | println!("\tcmp x0, x1"); 284 | println!("\tcset x0, NE"); 285 | } 286 | BinOpType::LessThan => { 287 | println!("\tcmp x0, x1"); 288 | println!("\tcset x0, LT"); 289 | } 290 | BinOpType::LessThanOrEqual => { 291 | println!("\tcmp x0, x1"); 292 | println!("\tcset x0, LE"); 293 | } 294 | } 295 | self.generate_push_register_to_stack("x0"); 296 | } 297 | } 298 | } 299 | 300 | fn increment_label_index(&self, label_index: &mut i32) -> i32 { 301 | let idx = *label_index; 302 | *label_index += 1; 303 | 304 | idx 305 | } 306 | 307 | fn generate_var(&self, node: &Node) { 308 | match &node.ast { 309 | Ast::LocalVar { offset, .. } => { 310 | println!("\tmov x0, {}", FRAME_POINTER_REGISTER); 311 | println!("\tsub x0, x0, #{}", offset); 312 | self.generate_push_register_to_stack("x0"); 313 | } 314 | Ast::GlobalVar { name } => { 315 | println!("\tadrp x0, _{}@GOTPAGE", name); 316 | println!("\tldr x0, [x0, _{}@GOTPAGEOFF]", name); 317 | self.generate_push_register_to_stack("x0"); 318 | } 319 | _ => { 320 | panic!("Node: {:?} is not local var", node); 321 | } 322 | } 323 | } 324 | 325 | fn load(&self, ty: &Option) { 326 | self.generate_comment(&format!("Load {:?} type value from x0", ty)); 327 | match *ty { 328 | Some(Ty::Array(..)) => { 329 | // 配列は先頭要素へのポインターとして扱うので、アドレスからロードはしない 330 | self.generate_comment("Treat array as pointer"); 331 | } 332 | Some(ref non_array_ty) => match non_array_ty.size() { 333 | 1 => println!("\tldrsb x0, [x0]"), 334 | 4 => println!("\tldrsw x0, [x0]"), 335 | 8 => println!("\tldr x0, [x0]"), 336 | _ => panic!("ty: {:?} is not supported", non_array_ty), 337 | }, 338 | None => { 339 | panic!("ty is None"); 340 | } 341 | } 342 | } 343 | 344 | fn store(&self, ty: &Option) { 345 | self.generate_comment(&format!("Store {:?} type value from x1", ty)); 346 | match *ty { 347 | Some(Ty::Array(..)) => { 348 | // Store array as pointer to head element 349 | println!("\tstr x1, [x0]"); 350 | } 351 | Some(ref non_array_ty) => match non_array_ty.size() { 352 | 1 => println!("\tstrb w1, [x0]"), 353 | 4 => println!("\tstr w1, [x0]"), 354 | 8 => println!("\tstr x1, [x0]"), 355 | _ => panic!("ty: {:?} is not supported", non_array_ty), 356 | }, 357 | None => { 358 | panic!("ty is None"); 359 | } 360 | } 361 | } 362 | 363 | fn generate_push_register_to_stack(&self, register: &str) { 364 | println!("\tstr {}, [sp, #-{}]!", register, STACK_ALIGNMENT); 365 | } 366 | 367 | fn generate_pop_register_from_stack(&self, register: &str) { 368 | println!("\tldr {}, [sp], #{}", register, STACK_ALIGNMENT); 369 | } 370 | 371 | fn generate_comment(&self, comment: &str) { 372 | println!("\t; {}", comment); 373 | } 374 | } 375 | -------------------------------------------------------------------------------- /src/tokenizer.rs: -------------------------------------------------------------------------------- 1 | mod token; 2 | mod token_list; 3 | use std::process::exit; 4 | 5 | use crate::error_report::error_at; 6 | 7 | pub use self::{ 8 | token::{Token, TokenKind}, 9 | token_list::TokenList, 10 | }; 11 | 12 | pub struct Tokenizer<'a> { 13 | original_input: &'a str, 14 | input: &'a str, 15 | pos: usize, 16 | } 17 | 18 | impl<'a> Tokenizer<'a> { 19 | pub fn new(input: &'a str) -> Tokenizer<'a> { 20 | Self { 21 | original_input: input, 22 | input, 23 | pos: 0, 24 | } 25 | } 26 | 27 | pub fn tokenize(mut self) -> TokenList<'a> { 28 | let mut tokens = vec![]; 29 | 30 | loop { 31 | self.skip_whitespace(); 32 | 33 | if self.input.is_empty() { 34 | break; 35 | } 36 | 37 | if self.try_consume("//") { 38 | let first_newline = self.input.find(|c| c == '\n').unwrap_or(self.input.len()); 39 | let (comment, rest_input) = self.input.split_at(first_newline); 40 | 41 | self.input = &rest_input[1..]; 42 | self.pos += comment.chars().count(); 43 | continue; 44 | } 45 | 46 | if self.try_consume("/*") { 47 | let first_newline = self.input.find("*/").unwrap_or(self.input.len()); 48 | let (comment, rest_input) = self.input.split_at(first_newline); 49 | 50 | self.input = &rest_input[2..]; 51 | self.pos += comment.chars().count() + 2; 52 | continue; 53 | } 54 | 55 | let current_position = self.pos; 56 | 57 | let reserved_symbolic_tokens = vec![ 58 | ("<=", TokenKind::LessThanOrEqual), 59 | (">=", TokenKind::GreaterThanOrEqual), 60 | ("==", TokenKind::Equal), 61 | ("!=", TokenKind::NotEqual), 62 | (">", TokenKind::GreaterThan), 63 | ("<", TokenKind::LessThan), 64 | ("+", TokenKind::Plus), 65 | ("-", TokenKind::Minus), 66 | ("*", TokenKind::Star), 67 | ("/", TokenKind::Div), 68 | ("(", TokenKind::LParen), 69 | (")", TokenKind::RParen), 70 | ("{", TokenKind::LBrace), 71 | ("}", TokenKind::RBrace), 72 | ("[", TokenKind::LBracket), 73 | ("]", TokenKind::RBracket), 74 | (";", TokenKind::Semicolon), 75 | ("=", TokenKind::Assign), 76 | (",", TokenKind::Comma), 77 | ("&", TokenKind::Ampersand), 78 | ]; 79 | let consumed_symbolic_token = reserved_symbolic_tokens 80 | .into_iter() 81 | .find(|(op, _)| self.try_consume(op)); 82 | if let Some((_, kind)) = consumed_symbolic_token { 83 | tokens.push(Token::new_syntax_item(current_position, kind)); 84 | continue; 85 | } 86 | 87 | if let Some(num) = self.try_consume_digits() { 88 | tokens.push(Token::new_num(current_position, num)); 89 | continue; 90 | } 91 | 92 | if self.try_consume("\"") { 93 | let first_double_quote = self.input.find(|c| c == '"').unwrap_or(self.input.len()); 94 | let (string_contents, rest_input) = self.input.split_at(first_double_quote); 95 | 96 | self.input = &rest_input[1..]; 97 | self.pos += string_contents.chars().count() + 1; 98 | tokens.push(Token::new_str( 99 | current_position, 100 | string_contents.to_string(), 101 | )); 102 | continue; 103 | } 104 | 105 | if let Some(c) = self.try_consume_alnum_or_underscore() { 106 | let reserved_identifiers = vec![ 107 | ("if", TokenKind::If), 108 | ("else", TokenKind::Else), 109 | ("return", TokenKind::Return), 110 | ("while", TokenKind::While), 111 | ("for", TokenKind::For), 112 | ("int", TokenKind::Int), 113 | ("char", TokenKind::Char), 114 | ("sizeof", TokenKind::SizeOf), 115 | ]; 116 | let consumed_identifier = reserved_identifiers.into_iter().find(|(id, _)| c == *id); 117 | if let Some((_, kind)) = consumed_identifier { 118 | tokens.push(Token::new_syntax_item(current_position, kind)); 119 | } else { 120 | tokens.push(Token::new_ident(current_position, &c)); 121 | } 122 | continue; 123 | } 124 | 125 | // 単純化のため、トークン化できなかったら即終了させる 126 | error_at(self.original_input, current_position, "Unrecognized token"); 127 | exit(1); 128 | } 129 | 130 | TokenList::new(self.original_input, tokens) 131 | } 132 | 133 | fn skip_whitespace(&mut self) { 134 | use itertools::Itertools; 135 | 136 | let mut chars = self.input.chars(); 137 | let spaces = chars 138 | .take_while_ref(|c| c.is_whitespace()) 139 | .collect::(); 140 | self.pos += spaces.chars().count(); 141 | self.input = chars.as_str(); 142 | } 143 | 144 | fn try_consume(&mut self, str: &str) -> bool { 145 | if self.input.starts_with(&str) { 146 | self.pos += str.chars().count(); 147 | self.input = &self.input[str.chars().count()..]; 148 | true 149 | } else { 150 | false 151 | } 152 | } 153 | 154 | fn try_consume_digits(&mut self) -> Option { 155 | let first_non_num = self 156 | .input 157 | .find(|c| !char::is_numeric(c)) 158 | .unwrap_or(self.input.len()); 159 | let (digit_str, rest_input) = self.input.split_at(first_non_num); 160 | 161 | match digit_str.parse::() { 162 | Ok(num) => { 163 | self.input = rest_input; 164 | self.pos += digit_str.chars().count(); 165 | Some(num) 166 | } 167 | Err(_) => None, 168 | } 169 | } 170 | 171 | fn try_consume_alnum_or_underscore(&mut self) -> Option { 172 | let first_non_alnum_or_underscore = self 173 | .input 174 | .find(|c| !(char::is_alphanumeric(c) || c == '_')) 175 | .unwrap_or(self.input.len()); 176 | let (alphabetic_str, rest_input) = self.input.split_at(first_non_alnum_or_underscore); 177 | 178 | self.input = rest_input; 179 | self.pos += alphabetic_str.chars().count(); 180 | Some(alphabetic_str.to_owned()) 181 | } 182 | } 183 | 184 | #[cfg(test)] 185 | mod tests { 186 | 187 | #[test] 188 | fn tokenize_single_digit_num() { 189 | let expr = "1"; 190 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 191 | assert_eq!(token_list.peek().unwrap().kind, super::TokenKind::Num); 192 | assert_eq!(token_list.peek().unwrap().num.unwrap(), 1); 193 | token_list.next(); 194 | assert!(token_list.peek().is_none()); 195 | } 196 | 197 | #[test] 198 | fn tokenize_multiple_digit_num() { 199 | let expr = "1234"; 200 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 201 | assert_eq!(token_list.peek().unwrap().kind, super::TokenKind::Num); 202 | assert_eq!(token_list.peek().unwrap().num.unwrap(), 1234); 203 | token_list.next(); 204 | assert!(token_list.peek().is_none()); 205 | } 206 | 207 | #[test] 208 | fn tokenize_operators() { 209 | let expr = "+-*/"; 210 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 211 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Plus); 212 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Minus); 213 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Star); 214 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Div); 215 | } 216 | 217 | #[test] 218 | fn tokenize_parens() { 219 | let expr = "()"; 220 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 221 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::LParen); 222 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::RParen); 223 | } 224 | 225 | #[test] 226 | fn skip_whitespaces() { 227 | let expr = "5 + 20 - 4"; 228 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 229 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Num); 230 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Plus); 231 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Num); 232 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Minus); 233 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Num); 234 | } 235 | 236 | #[test] 237 | fn tokenize_multi_length_operators() { 238 | let expr = "<=>===!=<>"; 239 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 240 | assert_eq!( 241 | token_list.next().unwrap().kind, 242 | super::TokenKind::LessThanOrEqual 243 | ); 244 | assert_eq!( 245 | token_list.next().unwrap().kind, 246 | super::TokenKind::GreaterThanOrEqual 247 | ); 248 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Equal); 249 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::NotEqual); 250 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::LessThan); 251 | assert_eq!( 252 | token_list.next().unwrap().kind, 253 | super::TokenKind::GreaterThan 254 | ); 255 | } 256 | 257 | #[test] 258 | fn tokenize_single_char_ident() { 259 | let expr = "a b"; 260 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 261 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Ident); 262 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Ident); 263 | } 264 | 265 | #[test] 266 | fn tokenize_single_multi_char_ident() { 267 | let expr = "foo bar"; 268 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 269 | let first_ident = token_list.next().unwrap(); 270 | let second_ident = token_list.next().unwrap(); 271 | assert_eq!(first_ident.kind, super::TokenKind::Ident); 272 | assert_eq!(first_ident.str.unwrap(), "foo"); 273 | assert_eq!(second_ident.kind, super::TokenKind::Ident); 274 | assert_eq!(second_ident.str.unwrap(), "bar"); 275 | } 276 | 277 | #[test] 278 | fn tokenize_semicolon() { 279 | let expr = ";"; 280 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 281 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Semicolon); 282 | } 283 | 284 | #[test] 285 | fn tokenize_equal_assign() { 286 | let expr = "==="; 287 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 288 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Equal); 289 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Assign); 290 | } 291 | 292 | #[test] 293 | fn tokenize_program() { 294 | let expr = "a = 42; a;"; 295 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 296 | // a = 42; 297 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Ident); 298 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Assign); 299 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Num); 300 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Semicolon); 301 | // a; 302 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Ident); 303 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Semicolon); 304 | } 305 | 306 | #[test] 307 | fn tokenize_return() { 308 | let expr = "return 42;"; 309 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 310 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Return); 311 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Num); 312 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Semicolon); 313 | } 314 | 315 | #[test] 316 | fn correctly_tokenize_return_like_local_var() { 317 | let expr = "return_with_suffix prefixed_return return42 return"; 318 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 319 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Ident); 320 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Ident); 321 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Ident); 322 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Return); 323 | } 324 | 325 | #[test] 326 | fn tokenize_if() { 327 | let expr = "prefixed_if if_with_suffix if"; 328 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 329 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Ident); 330 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Ident); 331 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::If); 332 | } 333 | 334 | #[test] 335 | fn tokenize_else() { 336 | let expr = "prefixed_else else_with_suffix else"; 337 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 338 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Ident); 339 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Ident); 340 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Else); 341 | } 342 | 343 | #[test] 344 | fn tokenize_while() { 345 | let expr = "prefixed_while while_with_suffix while"; 346 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 347 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Ident); 348 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Ident); 349 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::While); 350 | } 351 | 352 | #[test] 353 | fn tokenize_for() { 354 | let expr = "prefixed_for for_with_suffix for"; 355 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 356 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Ident); 357 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Ident); 358 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::For); 359 | } 360 | 361 | #[test] 362 | fn tokenize_brace() { 363 | let expr = "{}"; 364 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 365 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::LBrace); 366 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::RBrace); 367 | } 368 | 369 | #[test] 370 | fn tokenize_comma() { 371 | let expr = ","; 372 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 373 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Comma); 374 | } 375 | 376 | #[test] 377 | fn tokenize_ampersand() { 378 | let expr = "&"; 379 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 380 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Ampersand); 381 | } 382 | 383 | #[test] 384 | fn tokenize_int() { 385 | let expr = "int"; 386 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 387 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Int); 388 | } 389 | 390 | #[test] 391 | fn tokenize_sizeof() { 392 | let expr = "sizeof"; 393 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 394 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::SizeOf); 395 | } 396 | 397 | #[test] 398 | fn tokenize_bracket() { 399 | let expr = "[]"; 400 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 401 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::LBracket); 402 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::RBracket); 403 | } 404 | 405 | #[test] 406 | fn tokenize_char() { 407 | let expr = "prefixed_char char_with_suffix char"; 408 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 409 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Ident); 410 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Ident); 411 | assert_eq!(token_list.next().unwrap().kind, super::TokenKind::Char); 412 | } 413 | 414 | #[test] 415 | fn tokenize_string() { 416 | let expr = "\"hello, world\""; 417 | let mut token_list = super::Tokenizer::new(expr).tokenize(); 418 | let next_token = token_list.next().unwrap(); 419 | assert_eq!(next_token.kind, super::TokenKind::String); 420 | assert_eq!(next_token.str.unwrap(), "hello, world"); 421 | assert!(token_list.next().is_none()); 422 | } 423 | } 424 | -------------------------------------------------------------------------------- /src/parser.rs: -------------------------------------------------------------------------------- 1 | mod node; 2 | mod ty; 3 | mod var_env; 4 | 5 | pub use node::{Ast, BinOpType, Node}; 6 | 7 | use crate::tokenizer::{TokenKind, TokenList}; 8 | pub use ty::Ty; 9 | pub use var_env::StringLiteralEntry; 10 | 11 | use self::var_env::{GlobalVarInfo, LocalVarInfo, VarEnvironment, VarInfo}; 12 | 13 | pub struct Parser<'a> { 14 | token_list: TokenList<'a>, 15 | } 16 | 17 | impl<'a> Parser<'a> { 18 | pub fn new(token_list: TokenList<'a>) -> Parser<'a> { 19 | Self { token_list } 20 | } 21 | 22 | /* Lexing Programs */ 23 | pub fn program(&mut self) -> (Vec, Vec) { 24 | let mut nodes = vec![]; 25 | let mut var_env = VarEnvironment::new(); 26 | while !self.token_list.at_end() { 27 | nodes.push(self.top_level(&mut var_env)); 28 | } 29 | 30 | (nodes, var_env.string_literals) 31 | } 32 | 33 | fn top_level(&mut self, var_env: &mut VarEnvironment) -> Node { 34 | self.token_list.expect_kind(&TokenKind::Int); 35 | let mut ty = Ty::Int; 36 | ty = self.type_prefix(&ty); 37 | let ident_name = self.token_list.expect_kind(&TokenKind::Ident).str.unwrap(); 38 | // 次のトークンをのぞいてみて ( があれば、関数宣言, なければ変数宣言 39 | let next_token = self.token_list.peek().unwrap(); 40 | if next_token.kind == TokenKind::LParen { 41 | // assign offsets to local variables 42 | // スタックのトップには、FPとLRが保存されているので、-16以降が変数領域 43 | var_env.clear_local_variables(); 44 | let mut function_scope_var_env = var_env; 45 | let args = self.fundef_args(&mut function_scope_var_env); 46 | let body = self.fundef_body(&mut function_scope_var_env); 47 | let stack_size = function_scope_var_env.stack_size(); 48 | 49 | Node::new( 50 | Ast::Fundef { 51 | name: ident_name, 52 | args, 53 | body, 54 | stack_size, 55 | }, 56 | None, 57 | ) 58 | } else { 59 | ty = self.type_suffix(&ty); 60 | self.token_list.expect_kind(&TokenKind::Semicolon); 61 | var_env.add_global_var(&ident_name, ty.clone()); 62 | Node::new(Ast::GlobalVarDef(ident_name, ty), None) 63 | } 64 | } 65 | 66 | // int等のベースの型の後につづく*を読み込む 67 | fn type_prefix(&mut self, base_ty: &Ty) -> Ty { 68 | let mut ty = base_ty.clone(); 69 | while self.token_list.try_consume(&TokenKind::Star).is_some() { 70 | ty = Ty::Ptr(Box::new(ty)); 71 | } 72 | 73 | ty 74 | } 75 | 76 | // 識別子の後につづく[]のような型に影響をあたえる後置を読む 77 | fn type_suffix(&mut self, base_ty: &Ty) -> Ty { 78 | let mut ty = base_ty.clone(); 79 | let mut array_dimens = vec![]; 80 | while self.token_list.try_consume(&TokenKind::LBracket).is_some() { 81 | let dimen = self.token_list.expect_num(); 82 | array_dimens.push(dimen); 83 | self.token_list.expect_kind(&TokenKind::RBracket); 84 | } 85 | for dimen in array_dimens.iter().rev() { 86 | ty = Ty::Array(Box::new(ty), *dimen); 87 | } 88 | 89 | ty 90 | } 91 | 92 | fn fundef_args(&mut self, var_env: &mut VarEnvironment) -> Vec { 93 | let mut args = vec![]; 94 | self.token_list.expect_kind(&TokenKind::LParen); 95 | // 最大6つまでの引数をサポートする 96 | let mut paren_consumed = false; 97 | for _ in 1..=6 { 98 | if self.token_list.try_consume(&TokenKind::RParen).is_none() { 99 | self.token_list.expect_kind(&TokenKind::Int); 100 | let name = self.token_list.expect_kind(&TokenKind::Ident).str.unwrap(); 101 | let arg_var_info = var_env.add_local_var(&name, Ty::Int); 102 | args.push(Node::new( 103 | Ast::LocalVar { 104 | name, 105 | offset: arg_var_info.offset, 106 | }, 107 | Some(arg_var_info.ty), 108 | )); 109 | if self.token_list.try_consume(&TokenKind::RParen).is_none() { 110 | self.token_list.expect_kind(&TokenKind::Comma); 111 | } else { 112 | paren_consumed = true; 113 | break; 114 | } 115 | } else { 116 | paren_consumed = true; 117 | break; 118 | } 119 | } 120 | if !paren_consumed { 121 | self.token_list.expect_kind(&TokenKind::RParen); 122 | } 123 | 124 | args 125 | } 126 | 127 | fn fundef_body(&mut self, var_env: &mut VarEnvironment) -> Vec { 128 | self.token_list.expect_kind(&TokenKind::LBrace); 129 | let mut stmts = vec![]; 130 | while self.token_list.try_consume(&TokenKind::RBrace).is_none() { 131 | stmts.push(self.stmt(var_env)); 132 | } 133 | 134 | stmts 135 | } 136 | 137 | fn stmt(&mut self, var_env: &mut VarEnvironment) -> Node { 138 | if self.token_list.try_consume(&TokenKind::Int).is_some() { 139 | let mut ty = Ty::Int; 140 | ty = self.type_prefix(&ty); 141 | let ident_name = self.token_list.expect_kind(&TokenKind::Ident).str.unwrap(); 142 | ty = self.type_suffix(&ty); 143 | self.token_list.expect_kind(&TokenKind::Semicolon); 144 | var_env.add_local_var(&ident_name, ty.clone()); 145 | 146 | Node::new(Ast::LocalVarDef(ident_name, ty), None) 147 | } else if self.token_list.try_consume(&TokenKind::Char).is_some() { 148 | let mut ty = Ty::Char; 149 | ty = self.type_prefix(&ty); 150 | let ident_name = self.token_list.expect_kind(&TokenKind::Ident).str.unwrap(); 151 | ty = self.type_suffix(&ty); 152 | self.token_list.expect_kind(&TokenKind::Semicolon); 153 | var_env.add_local_var(&ident_name, ty.clone()); 154 | 155 | Node::new(Ast::LocalVarDef(ident_name, ty), None) 156 | } else if self.token_list.try_consume(&TokenKind::Return).is_some() { 157 | let return_value = self.expr(var_env); 158 | self.token_list.expect_kind(&TokenKind::Semicolon); 159 | 160 | Node::new(Ast::Return(Box::new(return_value)), None) 161 | } else if self.token_list.try_consume(&TokenKind::If).is_some() { 162 | self.token_list.expect_kind(&TokenKind::LParen); 163 | let condition = self.expr(var_env); 164 | self.token_list.expect_kind(&TokenKind::RParen); 165 | let then_body = self.stmt(var_env); 166 | 167 | if self.token_list.try_consume(&TokenKind::Else).is_some() { 168 | let else_body = self.stmt(var_env); 169 | 170 | return Node::new( 171 | Ast::If( 172 | Box::new(condition), 173 | Box::new(then_body), 174 | Some(Box::new(else_body)), 175 | ), 176 | None, 177 | ); 178 | } 179 | 180 | Node::new( 181 | Ast::If(Box::new(condition), Box::new(then_body), None), 182 | None, 183 | ) 184 | } else if self.token_list.try_consume(&TokenKind::While).is_some() { 185 | self.token_list.expect_kind(&TokenKind::LParen); 186 | let condition = self.expr(var_env); 187 | self.token_list.expect_kind(&TokenKind::RParen); 188 | let body = self.stmt(var_env); 189 | 190 | Node::new(Ast::While(Box::new(condition), Box::new(body)), None) 191 | } else if self.token_list.try_consume(&TokenKind::For).is_some() { 192 | // forの後には、for (初期化; 条件; 更新) 本体 193 | // ただし、初期化, 条件, 更新はどれも省略可能 194 | self.token_list.expect_kind(&TokenKind::LParen); 195 | let init = if self.token_list.try_consume(&TokenKind::Semicolon).is_some() { 196 | None 197 | } else { 198 | let node = self.expr(var_env); 199 | self.token_list.expect_kind(&TokenKind::Semicolon); 200 | 201 | Some(Box::new(node)) 202 | }; 203 | let check = if self.token_list.try_consume(&TokenKind::Semicolon).is_some() { 204 | None 205 | } else { 206 | let node = self.expr(var_env); 207 | self.token_list.expect_kind(&TokenKind::Semicolon); 208 | 209 | Some(Box::new(node)) 210 | }; 211 | let update = if self.token_list.try_consume(&TokenKind::RParen).is_some() { 212 | None 213 | } else { 214 | let node = self.expr(var_env); 215 | self.token_list.expect_kind(&TokenKind::RParen); 216 | 217 | Some(Box::new(node)) 218 | }; 219 | 220 | let body = self.stmt(var_env); 221 | Node::new(Ast::For(init, check, update, Box::new(body)), None) 222 | } else if self.token_list.try_consume(&TokenKind::LBrace).is_some() { 223 | let mut stmts = vec![]; 224 | while self.token_list.try_consume(&TokenKind::RBrace).is_none() { 225 | stmts.push(self.stmt(var_env)); 226 | } 227 | 228 | Node::new(Ast::Block(stmts), None) 229 | } else if let Some(lvar) = self.local_var(var_env) { 230 | lvar 231 | } else { 232 | let expr = self.expr(var_env); 233 | self.token_list.expect_kind(&TokenKind::Semicolon); 234 | 235 | expr 236 | } 237 | } 238 | 239 | fn local_var(&mut self, var_env: &mut VarEnvironment) -> Option { 240 | let mut ty; 241 | if self.token_list.try_consume(&TokenKind::Int).is_some() { 242 | ty = Ty::Int; 243 | } else if self.token_list.try_consume(&TokenKind::Char).is_some() { 244 | ty = Ty::Char; 245 | } else { 246 | // Local var should start from type name; 247 | return None; 248 | } 249 | 250 | ty = self.type_prefix(&ty); 251 | let ident_name = self.token_list.expect_kind(&TokenKind::Ident).str.unwrap(); 252 | ty = self.type_suffix(&ty); 253 | self.token_list.expect_kind(&TokenKind::Semicolon); 254 | var_env.add_local_var(&ident_name, ty.clone()); 255 | 256 | Some(Node::new(Ast::LocalVarDef(ident_name, ty), None)) 257 | } 258 | 259 | fn expr(&mut self, var_env: &mut VarEnvironment) -> Node { 260 | self.assign(var_env) 261 | } 262 | 263 | fn assign(&mut self, var_env: &mut VarEnvironment) -> Node { 264 | let mut node = self.equality(var_env); 265 | if self.token_list.try_consume(&TokenKind::Assign).is_some() { 266 | let lhs = node; 267 | if let Some(Ty::Array(..)) = lhs.ty { 268 | panic!("{:?} is not a lvalue", lhs) 269 | } 270 | let lhs_ty = lhs.ty.clone(); 271 | let rhs = self.assign(var_env); 272 | node = Node::new(Ast::Assign(Box::new(lhs), Box::new(rhs)), lhs_ty); 273 | } 274 | 275 | node 276 | } 277 | 278 | fn equality(&mut self, var_env: &mut VarEnvironment) -> Node { 279 | let mut node = self.relational(var_env); 280 | 281 | loop { 282 | if self.token_list.try_consume(&TokenKind::Equal).is_some() { 283 | let lhs = node; 284 | let rhs = self.relational(var_env); 285 | node = Node::new( 286 | Ast::BinOp(BinOpType::Equal, Box::new(lhs), Box::new(rhs)), 287 | Some(Ty::Int), 288 | ); 289 | } else if self.token_list.try_consume(&TokenKind::NotEqual).is_some() { 290 | let lhs = node; 291 | let rhs = self.relational(var_env); 292 | node = Node::new( 293 | Ast::BinOp(BinOpType::NotEqual, Box::new(lhs), Box::new(rhs)), 294 | Some(Ty::Int), 295 | ); 296 | } else { 297 | return node; 298 | } 299 | } 300 | } 301 | 302 | fn relational(&mut self, var_env: &mut VarEnvironment) -> Node { 303 | let mut node = self.add(var_env); 304 | 305 | loop { 306 | if self.token_list.try_consume(&TokenKind::LessThan).is_some() { 307 | let lhs = node; 308 | let rhs = self.add(var_env); 309 | node = Node::new( 310 | Ast::BinOp(BinOpType::LessThan, Box::new(lhs), Box::new(rhs)), 311 | Some(Ty::Int), 312 | ); 313 | } else if self 314 | .token_list 315 | .try_consume(&TokenKind::LessThanOrEqual) 316 | .is_some() 317 | { 318 | let lhs = node; 319 | let rhs = self.add(var_env); 320 | node = Node::new( 321 | Ast::BinOp(BinOpType::LessThanOrEqual, Box::new(lhs), Box::new(rhs)), 322 | Some(Ty::Int), 323 | ); 324 | } else if self 325 | .token_list 326 | .try_consume(&TokenKind::GreaterThan) 327 | .is_some() 328 | { 329 | let lhs = self.add(var_env); 330 | let rhs = node; 331 | node = Node::new( 332 | Ast::BinOp(BinOpType::LessThan, Box::new(lhs), Box::new(rhs)), 333 | Some(Ty::Int), 334 | ); 335 | } else if self 336 | .token_list 337 | .try_consume(&TokenKind::GreaterThanOrEqual) 338 | .is_some() 339 | { 340 | let lhs = self.add(var_env); 341 | let rhs = node; 342 | node = Node::new( 343 | Ast::BinOp(BinOpType::LessThanOrEqual, Box::new(lhs), Box::new(rhs)), 344 | Some(Ty::Int), 345 | ); 346 | } else { 347 | return node; 348 | } 349 | } 350 | } 351 | 352 | fn add(&mut self, var_env: &mut VarEnvironment) -> Node { 353 | let mut node = self.mul(var_env); 354 | 355 | loop { 356 | if self.token_list.try_consume(&TokenKind::Plus).is_some() { 357 | let lhs = node; 358 | let lhs_ty = lhs.ty.clone(); 359 | let mut rhs = self.mul(var_env); 360 | if let Some(ref lhs_ty) = lhs_ty { 361 | if lhs_ty.is_reference_type() { 362 | rhs = Node::new( 363 | Ast::BinOp( 364 | BinOpType::Mul, 365 | Box::new(rhs), 366 | Box::new(Node::new( 367 | Ast::Num(lhs_ty.clone().base_ty().size()), 368 | Some(Ty::Int), 369 | )), 370 | ), 371 | Some(Ty::Int), 372 | ); 373 | node = Node::new( 374 | Ast::BinOp(BinOpType::Add, Box::new(lhs), Box::new(rhs)), 375 | Some(lhs_ty.clone()), 376 | ); 377 | } else { 378 | node = Node::new( 379 | Ast::BinOp(BinOpType::Add, Box::new(lhs), Box::new(rhs)), 380 | Some(lhs_ty.clone()), 381 | ); 382 | } 383 | } else { 384 | unreachable!(); 385 | } 386 | } else if self.token_list.try_consume(&TokenKind::Minus).is_some() { 387 | let lhs = node; 388 | let lhs_ty = lhs.ty.clone(); 389 | let mut rhs = self.mul(var_env); 390 | match &lhs_ty { 391 | Some(Ty::Int) => { 392 | node = Node::new( 393 | Ast::BinOp(BinOpType::Sub, Box::new(lhs), Box::new(rhs)), 394 | lhs_ty.clone(), 395 | ); 396 | } 397 | //何かの値の参照をしている型は、参照先の型のサイズに応じてスケールする必要があるので欠け算のノードを挟んでおく 398 | Some(refrence_type) => { 399 | rhs = Node::new( 400 | Ast::BinOp( 401 | BinOpType::Mul, 402 | Box::new(rhs), 403 | Box::new(Node::new( 404 | Ast::Num(refrence_type.base_ty().size()), 405 | Some(Ty::Int), 406 | )), 407 | ), 408 | Some(Ty::Int), 409 | ); 410 | node = Node::new( 411 | Ast::BinOp(BinOpType::Sub, Box::new(lhs), Box::new(rhs)), 412 | lhs_ty.clone(), 413 | ); 414 | } 415 | None => unreachable!(), 416 | } 417 | } else { 418 | return node; 419 | } 420 | } 421 | } 422 | 423 | fn mul(&mut self, var_env: &mut VarEnvironment) -> Node { 424 | let mut node = self.unary(var_env); 425 | let mut node_ty = node.ty.clone(); 426 | 427 | loop { 428 | if self.token_list.try_consume(&TokenKind::Star).is_some() { 429 | let lhs = node; 430 | let rhs = self.unary(var_env); 431 | node = Node::new( 432 | Ast::BinOp(BinOpType::Mul, Box::new(lhs), Box::new(rhs)), 433 | node_ty, 434 | ); 435 | node_ty = node.ty.clone(); 436 | } else if self.token_list.try_consume(&TokenKind::Div).is_some() { 437 | let lhs = node; 438 | let rhs = self.unary(var_env); 439 | node = Node::new( 440 | Ast::BinOp(BinOpType::Div, Box::new(lhs), Box::new(rhs)), 441 | node_ty, 442 | ); 443 | node_ty = node.ty.clone(); 444 | } else { 445 | return node; 446 | } 447 | } 448 | } 449 | 450 | fn unary(&mut self, var_env: &mut VarEnvironment) -> Node { 451 | if self.token_list.try_consume(&TokenKind::SizeOf).is_some() { 452 | let node = self.unary(var_env); 453 | let node_ty = node.ty.unwrap(); 454 | return Node::new(Ast::Num(node_ty.size()), Some(Ty::Int)); 455 | } 456 | if self.token_list.try_consume(&TokenKind::Plus).is_some() { 457 | // TODO: should check to_ptr_if_array? 458 | return self.primary(var_env); 459 | } 460 | if self.token_list.try_consume(&TokenKind::Minus).is_some() { 461 | let rhs = self.primary(var_env); 462 | return Node::new( 463 | Ast::BinOp( 464 | BinOpType::Sub, 465 | Box::new(Node::new(Ast::Num(0), Some(Ty::Int))), 466 | Box::new(rhs), 467 | ), 468 | Some(Ty::Int), 469 | ); 470 | } 471 | if self.token_list.try_consume(&TokenKind::Star).is_some() { 472 | let base = self.unary(var_env); 473 | let base_ty = base.ty.clone(); 474 | return Node::new(Ast::Deref(Box::new(base)), Some(base_ty.unwrap().base_ty())); 475 | } 476 | if self.token_list.try_consume(&TokenKind::Ampersand).is_some() { 477 | let base = self.unary(var_env); 478 | let base_ty = base.ty.clone().unwrap(); 479 | match base_ty { 480 | Ty::Array(item_ty, ..) => { 481 | return Node::new(Ast::Addr(Box::new(base)), Some(Ty::Ptr(item_ty))); 482 | } 483 | _ => { 484 | return Node::new(Ast::Addr(Box::new(base)), Some(Ty::Ptr(Box::new(base_ty)))); 485 | } 486 | } 487 | } 488 | self.primary(var_env) 489 | } 490 | 491 | fn primary(&mut self, var_env: &mut VarEnvironment) -> Node { 492 | if self.token_list.try_consume(&TokenKind::LParen).is_some() { 493 | let node = self.expr(var_env); 494 | self.token_list.expect_kind(&TokenKind::RParen); 495 | return node; 496 | } else if let Some(ident_tok) = self.token_list.try_consume(&TokenKind::Ident) { 497 | let ident_name = ident_tok.str.unwrap(); 498 | if self.token_list.try_consume(&TokenKind::LParen).is_some() { 499 | // 最大6つまでの引数をサポートする 500 | let mut args = vec![]; 501 | let mut paren_consumed = false; 502 | for _ in 1..=6 { 503 | if self.token_list.try_consume(&TokenKind::RParen).is_none() { 504 | let arg = self.expr(var_env); 505 | args.push(arg); 506 | if self.token_list.try_consume(&TokenKind::RParen).is_none() { 507 | self.token_list.expect_kind(&TokenKind::Comma); 508 | } else { 509 | paren_consumed = true; 510 | break; 511 | } 512 | } else { 513 | paren_consumed = true; 514 | break; 515 | } 516 | } 517 | if !paren_consumed { 518 | self.token_list.expect_kind(&TokenKind::RParen); 519 | } 520 | // 今はint しかサポートしていない 521 | return Node::new(Ast::Funcall(ident_name, args), Some(Ty::Int)); 522 | } else if let Some(var_info) = var_env.resolve(&ident_name) { 523 | let mut node; 524 | let mut node_ty; 525 | match var_info { 526 | VarInfo::Global(GlobalVarInfo { 527 | ty: global_var_ty, 528 | label, 529 | }) => { 530 | node = 531 | Node::new(Ast::GlobalVar { name: label }, Some(global_var_ty.clone())); 532 | node_ty = global_var_ty; 533 | } 534 | VarInfo::Local(LocalVarInfo { 535 | ty: local_var_ty, 536 | offset, 537 | }) => { 538 | node = Node::new( 539 | Ast::LocalVar { 540 | name: ident_name, 541 | offset, 542 | }, 543 | Some(local_var_ty.clone()), 544 | ); 545 | node_ty = local_var_ty; 546 | } 547 | } 548 | // 配列の要素を取りだす構文 x[y][z] をサポート 549 | let mut array_dimens = vec![]; 550 | while self.token_list.try_consume(&TokenKind::LBracket).is_some() { 551 | let dimen = self.token_list.expect_num(); 552 | array_dimens.push(dimen); 553 | self.token_list.expect_kind(&TokenKind::RBracket); 554 | } 555 | for dimen in array_dimens.iter().rev() { 556 | node = Node::new( 557 | Ast::Deref(Box::new(Node::new( 558 | Ast::BinOp( 559 | BinOpType::Add, 560 | Box::new(node), 561 | Box::new(Node::new(Ast::Num(*dimen), Some(Ty::Int))), 562 | ), 563 | Some(node_ty.clone()), 564 | ))), 565 | Some(node_ty.base_ty()), 566 | ); 567 | node_ty = node_ty.base_ty(); 568 | } 569 | return node; 570 | } else { 571 | panic!("undefined variable: {}", ident_name); 572 | } 573 | } else if let Some(str_literal) = self.token_list.try_consume(&TokenKind::String) { 574 | let label = var_env.add_string_literal(&str_literal.str.clone().unwrap()); 575 | return Node::new( 576 | Ast::StringLiteral { label: label }, 577 | Some(Ty::Array( 578 | Box::new(Ty::Char), 579 | str_literal.str.unwrap().len() as i32, 580 | )), 581 | ); 582 | } 583 | 584 | let n = self.token_list.expect_num(); 585 | Node::new(Ast::Num(n), Some(Ty::Int)) 586 | } 587 | } 588 | --------------------------------------------------------------------------------