Compare commits
3 Commits
5a09699845
...
43a20c99f6
| Author | SHA1 | Date | |
|---|---|---|---|
|
43a20c99f6
|
|||
|
6fe971c615
|
|||
|
8ad69be5aa
|
@@ -77,14 +77,12 @@ pub struct CodegenX86_64<'a> {
|
|||||||
data_counter: usize,
|
data_counter: usize,
|
||||||
pub symbol_table: &'a SymbolTable,
|
pub symbol_table: &'a SymbolTable,
|
||||||
pub expr_types: &'a HashMap<usize, String>,
|
pub expr_types: &'a HashMap<usize, String>,
|
||||||
emit_debug: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CodegenX86_64<'a> {
|
impl<'a> CodegenX86_64<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
symbol_table: &'a SymbolTable,
|
symbol_table: &'a SymbolTable,
|
||||||
expr_types: &'a HashMap<usize, String>,
|
expr_types: &'a HashMap<usize, String>,
|
||||||
emit_debug: bool,
|
|
||||||
) -> CodegenX86_64<'a> {
|
) -> CodegenX86_64<'a> {
|
||||||
CodegenX86_64 {
|
CodegenX86_64 {
|
||||||
output: String::new(),
|
output: String::new(),
|
||||||
@@ -93,7 +91,6 @@ impl<'a> CodegenX86_64<'a> {
|
|||||||
data_counter: 1,
|
data_counter: 1,
|
||||||
symbol_table,
|
symbol_table,
|
||||||
expr_types,
|
expr_types,
|
||||||
emit_debug,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,58 +100,60 @@ impl<'a> CodegenX86_64<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_output(&self) -> String {
|
pub fn get_output(&self) -> String {
|
||||||
format!("section .data\n{}{}", self.data_section, self.output)
|
format!(".section .data\n{}{}", self.data_section, self.output)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn emit_prologue(&mut self, use_crt: bool) -> Result<(), ZernError> {
|
pub fn emit_prologue(&mut self, use_crt: bool) -> Result<(), ZernError> {
|
||||||
emit!(
|
emit!(
|
||||||
&mut self.output,
|
&mut self.output,
|
||||||
"section .note.GNU-stack
|
".intel_syntax noprefix
|
||||||
db 0
|
|
||||||
|
|
||||||
section .bss
|
.section .note.GNU-stack
|
||||||
_heap_head: resq 1
|
.byte 0
|
||||||
_heap_tail: resq 1
|
|
||||||
_environ: resq 1
|
|
||||||
|
|
||||||
section .text._builtin_heap_head
|
.section .bss
|
||||||
|
_heap_head: .zero 8
|
||||||
|
_heap_tail: .zero 8
|
||||||
|
_environ: .zero 8
|
||||||
|
|
||||||
|
.section .text._builtin_heap_head
|
||||||
_builtin_heap_head:
|
_builtin_heap_head:
|
||||||
lea rax, [rel _heap_head]
|
lea rax, [rip + _heap_head]
|
||||||
ret
|
ret
|
||||||
|
|
||||||
section .text._builtin_heap_tail
|
.section .text._builtin_heap_tail
|
||||||
_builtin_heap_tail:
|
_builtin_heap_tail:
|
||||||
lea rax, [rel _heap_tail]
|
lea rax, [rip + _heap_tail]
|
||||||
ret
|
ret
|
||||||
|
|
||||||
section .text._builtin_read64
|
.section .text._builtin_read64
|
||||||
_builtin_read64:
|
_builtin_read64:
|
||||||
mov rax, QWORD [rdi]
|
mov rax, QWORD PTR [rdi]
|
||||||
ret
|
ret
|
||||||
|
|
||||||
section .text._builtin_set64
|
.section .text._builtin_set64
|
||||||
_builtin_set64:
|
_builtin_set64:
|
||||||
mov [rdi], rsi
|
mov [rdi], rsi
|
||||||
ret
|
ret
|
||||||
|
|
||||||
section .text._builtin_cvtsi2sd
|
.section .text._builtin_cvtsi2sd
|
||||||
_builtin_cvtsi2sd:
|
_builtin_cvtsi2sd:
|
||||||
cvtsi2sd xmm0, rdi
|
cvtsi2sd xmm0, rdi
|
||||||
movq rax, xmm0
|
movq rax, xmm0
|
||||||
ret
|
ret
|
||||||
|
|
||||||
section .text._builtin_cvttsd2si
|
.section .text._builtin_cvttsd2si
|
||||||
_builtin_cvttsd2si:
|
_builtin_cvttsd2si:
|
||||||
cvttsd2si rax, xmm0
|
cvttsd2si rax, xmm0
|
||||||
ret
|
ret
|
||||||
|
|
||||||
section .text._builtin_f64_to_float
|
.section .text._builtin_f64_to_float
|
||||||
_builtin_f64_to_float:
|
_builtin_f64_to_float:
|
||||||
cvtsd2ss xmm0, xmm0
|
cvtsd2ss xmm0, xmm0
|
||||||
movd eax, xmm0
|
movd eax, xmm0
|
||||||
ret
|
ret
|
||||||
|
|
||||||
section .text._builtin_syscall
|
.section .text._builtin_syscall
|
||||||
_builtin_syscall:
|
_builtin_syscall:
|
||||||
mov rax, rdi
|
mov rax, rdi
|
||||||
mov rdi, rsi
|
mov rdi, rsi
|
||||||
@@ -172,26 +171,26 @@ _builtin_syscall:
|
|||||||
emit!(
|
emit!(
|
||||||
&mut self.output,
|
&mut self.output,
|
||||||
"
|
"
|
||||||
section .text._builtin_environ
|
.section .text._builtin_environ
|
||||||
_builtin_environ:
|
_builtin_environ:
|
||||||
lea rax, [rel _environ]
|
lea rax, [rip + _environ]
|
||||||
mov rax, [rax]
|
mov rax, [rax]
|
||||||
ret
|
ret
|
||||||
|
|
||||||
global _start
|
.globl _start
|
||||||
section .text
|
.section .text
|
||||||
_start:
|
_start:
|
||||||
xor rbp, rbp
|
xor rbp, rbp
|
||||||
; setup args
|
// setup args
|
||||||
pop rdi
|
pop rdi
|
||||||
mov rsi, rsp
|
mov rsi, rsp
|
||||||
; save environ
|
// save environ
|
||||||
lea rdx, [rsi + rdi*8 + 8]
|
lea rdx, [rsi + rdi*8 + 8]
|
||||||
lea rax, [rel _environ]
|
lea rax, [rip + _environ]
|
||||||
mov [rax], rdx
|
mov [rax], rdx
|
||||||
; align stack
|
// align stack
|
||||||
and rsp, -16
|
and rsp, -16
|
||||||
; exit(main())
|
// exit(main())
|
||||||
call main
|
call main
|
||||||
mov rdi, rax
|
mov rdi, rax
|
||||||
mov rax, 60
|
mov rax, 60
|
||||||
@@ -202,10 +201,10 @@ _start:
|
|||||||
emit!(
|
emit!(
|
||||||
&mut self.output,
|
&mut self.output,
|
||||||
"
|
"
|
||||||
section .text._builtin_environ
|
.section .text._builtin_environ
|
||||||
_builtin_environ:
|
_builtin_environ:
|
||||||
extern environ
|
.extern environ
|
||||||
mov rax, [rel environ]
|
mov rax, [rip + environ]
|
||||||
ret
|
ret
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
@@ -239,7 +238,7 @@ _builtin_environ:
|
|||||||
|
|
||||||
self.compile_expr(env, initializer)?;
|
self.compile_expr(env, initializer)?;
|
||||||
let offset = env.define_var(name.lexeme.clone(), var_type);
|
let offset = env.define_var(name.lexeme.clone(), var_type);
|
||||||
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset);
|
emit!(&mut self.output, " mov QWORD PTR [rbp-{}], rax", offset);
|
||||||
}
|
}
|
||||||
Stmt::Assign { left, op, value } => {
|
Stmt::Assign { left, op, value } => {
|
||||||
self.compile_expr(env, value)?;
|
self.compile_expr(env, value)?;
|
||||||
@@ -250,7 +249,7 @@ _builtin_environ:
|
|||||||
let var = env.get_var(&name.lexeme).unwrap();
|
let var = env.get_var(&name.lexeme).unwrap();
|
||||||
emit!(
|
emit!(
|
||||||
&mut self.output,
|
&mut self.output,
|
||||||
" mov QWORD [rbp-{}], rax",
|
" mov QWORD PTR [rbp-{}], rax",
|
||||||
var.stack_offset,
|
var.stack_offset,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -266,7 +265,7 @@ _builtin_environ:
|
|||||||
emit!(&mut self.output, " pop rbx");
|
emit!(&mut self.output, " pop rbx");
|
||||||
emit!(&mut self.output, " add rbx, rax");
|
emit!(&mut self.output, " add rbx, rax");
|
||||||
emit!(&mut self.output, " pop rax");
|
emit!(&mut self.output, " pop rax");
|
||||||
emit!(&mut self.output, " mov BYTE [rbx], al");
|
emit!(&mut self.output, " mov BYTE PTR [rbx], al");
|
||||||
}
|
}
|
||||||
ExprKind::MemberAccess { left, field } => {
|
ExprKind::MemberAccess { left, field } => {
|
||||||
emit!(&mut self.output, " push rax");
|
emit!(&mut self.output, " push rax");
|
||||||
@@ -275,7 +274,7 @@ _builtin_environ:
|
|||||||
|
|
||||||
self.compile_expr(env, left)?;
|
self.compile_expr(env, left)?;
|
||||||
emit!(&mut self.output, " pop rbx");
|
emit!(&mut self.output, " pop rbx");
|
||||||
emit!(&mut self.output, " mov QWORD [rax+{}], rbx", offset);
|
emit!(&mut self.output, " mov QWORD PTR [rax+{}], rbx", offset);
|
||||||
}
|
}
|
||||||
_ => return error!(&op.loc, "invalid assignment target"),
|
_ => return error!(&op.loc, "invalid assignment target"),
|
||||||
};
|
};
|
||||||
@@ -302,7 +301,12 @@ _builtin_environ:
|
|||||||
env.define_var(target.lexeme.clone(), types[i].to_string())
|
env.define_var(target.lexeme.clone(), types[i].to_string())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
emit!(&mut self.output, " mov QWORD [rbp-{}], {}", offset, reg);
|
emit!(
|
||||||
|
&mut self.output,
|
||||||
|
" mov QWORD PTR [rbp-{}], {}",
|
||||||
|
offset,
|
||||||
|
reg
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Stmt::Const { .. } => {
|
Stmt::Const { .. } => {
|
||||||
@@ -365,14 +369,11 @@ _builtin_environ:
|
|||||||
exported,
|
exported,
|
||||||
} => {
|
} => {
|
||||||
let name = &name.lexeme;
|
let name = &name.lexeme;
|
||||||
if self.emit_debug || *exported || name == "main" {
|
if *exported || name == "main" {
|
||||||
emit!(
|
emit!(&mut self.output, ".globl {0}", name);
|
||||||
&mut self.output,
|
|
||||||
"global {0}:function ({0}.end - {0})",
|
|
||||||
name
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
emit!(&mut self.output, "section .text.{}", name);
|
emit!(&mut self.output, ".type {0}, @function", name);
|
||||||
|
emit!(&mut self.output, ".section .text.{}", name);
|
||||||
emit!(&mut self.output, "{}:", name);
|
emit!(&mut self.output, "{}:", name);
|
||||||
emit!(&mut self.output, " push rbp");
|
emit!(&mut self.output, " push rbp");
|
||||||
emit!(&mut self.output, " mov rbp, rsp");
|
emit!(&mut self.output, " mov rbp, rsp");
|
||||||
@@ -388,15 +389,20 @@ _builtin_environ:
|
|||||||
param.var_type.lexeme.clone(),
|
param.var_type.lexeme.clone(),
|
||||||
);
|
);
|
||||||
if let Some(reg) = REGISTERS.get(i) {
|
if let Some(reg) = REGISTERS.get(i) {
|
||||||
emit!(&mut self.output, " mov QWORD [rbp-{}], {}", offset, reg);
|
emit!(
|
||||||
|
&mut self.output,
|
||||||
|
" mov QWORD PTR [rbp-{}], {}",
|
||||||
|
offset,
|
||||||
|
reg
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
let stack_offset = 16 + 8 * (i - REGISTERS.len());
|
let stack_offset = 16 + 8 * (i - REGISTERS.len());
|
||||||
emit!(
|
emit!(
|
||||||
&mut self.output,
|
&mut self.output,
|
||||||
" mov rax, QWORD [rbp+{}]",
|
" mov rax, QWORD PTR [rbp+{}]",
|
||||||
stack_offset
|
stack_offset
|
||||||
);
|
);
|
||||||
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset);
|
emit!(&mut self.output, " mov QWORD PTR [rbp-{}], rax", offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -423,7 +429,7 @@ _builtin_environ:
|
|||||||
emit!(&mut self.output, " ret");
|
emit!(&mut self.output, " ret");
|
||||||
}
|
}
|
||||||
|
|
||||||
emit!(&mut self.output, ".end:");
|
emit!(&mut self.output, ".size {0}, . - {0}", name);
|
||||||
|
|
||||||
// patch the stack size after we know how much we actually need
|
// patch the stack size after we know how much we actually need
|
||||||
let patch = format!(" sub rsp, {:<10}", (env.next_offset + 15) & !15);
|
let patch = format!(" sub rsp, {:<10}", (env.next_offset + 15) & !15);
|
||||||
@@ -465,21 +471,29 @@ _builtin_environ:
|
|||||||
let offset = env.define_var(var.lexeme.clone(), "i64".into());
|
let offset = env.define_var(var.lexeme.clone(), "i64".into());
|
||||||
|
|
||||||
self.compile_expr(env, start)?;
|
self.compile_expr(env, start)?;
|
||||||
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset);
|
emit!(&mut self.output, " mov QWORD PTR [rbp-{}], rax", offset);
|
||||||
self.compile_expr(env, end)?;
|
self.compile_expr(env, end)?;
|
||||||
let end_offset = env.next_offset;
|
let end_offset = env.next_offset;
|
||||||
env.next_offset += 8;
|
env.next_offset += 8;
|
||||||
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", end_offset);
|
emit!(
|
||||||
|
&mut self.output,
|
||||||
|
" mov QWORD PTR [rbp-{}], rax",
|
||||||
|
end_offset
|
||||||
|
);
|
||||||
emit!(&mut self.output, "{}:", env.loop_begin_label);
|
emit!(&mut self.output, "{}:", env.loop_begin_label);
|
||||||
emit!(&mut self.output, " mov rax, QWORD [rbp-{}]", offset);
|
emit!(&mut self.output, " mov rax, QWORD PTR [rbp-{}]", offset);
|
||||||
emit!(&mut self.output, " mov rcx, QWORD [rbp-{}]", end_offset);
|
emit!(
|
||||||
|
&mut self.output,
|
||||||
|
" mov rcx, QWORD PTR [rbp-{}]",
|
||||||
|
end_offset
|
||||||
|
);
|
||||||
emit!(&mut self.output, " cmp rax, rcx");
|
emit!(&mut self.output, " cmp rax, rcx");
|
||||||
emit!(&mut self.output, " jge {}", env.loop_end_label);
|
emit!(&mut self.output, " jge {}", env.loop_end_label);
|
||||||
self.compile_stmt(env, body)?;
|
self.compile_stmt(env, body)?;
|
||||||
emit!(&mut self.output, "{}:", env.loop_continue_label);
|
emit!(&mut self.output, "{}:", env.loop_continue_label);
|
||||||
emit!(&mut self.output, " mov rax, QWORD [rbp-{}]", offset);
|
emit!(&mut self.output, " mov rax, QWORD PTR [rbp-{}]", offset);
|
||||||
emit!(&mut self.output, " add rax, 1");
|
emit!(&mut self.output, " add rax, 1");
|
||||||
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset);
|
emit!(&mut self.output, " mov QWORD PTR [rbp-{}], rax", offset);
|
||||||
emit!(&mut self.output, " jmp {}", env.loop_begin_label);
|
emit!(&mut self.output, " jmp {}", env.loop_begin_label);
|
||||||
emit!(&mut self.output, "{}:", env.loop_end_label);
|
emit!(&mut self.output, "{}:", env.loop_end_label);
|
||||||
env.pop_scope();
|
env.pop_scope();
|
||||||
@@ -495,14 +509,11 @@ _builtin_environ:
|
|||||||
emit!(&mut self.output, " jmp {}", env.loop_continue_label);
|
emit!(&mut self.output, " jmp {}", env.loop_continue_label);
|
||||||
}
|
}
|
||||||
Stmt::Extern(name) => {
|
Stmt::Extern(name) => {
|
||||||
emit!(&mut self.output, "extern {}", name.lexeme);
|
emit!(&mut self.output, ".extern {}", name.lexeme);
|
||||||
}
|
}
|
||||||
Stmt::Struct { .. } => {
|
Stmt::Struct { .. } => {
|
||||||
// handled in SymbolTable
|
// handled in SymbolTable
|
||||||
}
|
}
|
||||||
Stmt::Enum { .. } => {
|
|
||||||
// handled in SymbolTable
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -610,11 +621,8 @@ _builtin_environ:
|
|||||||
emit!(&mut self.output, " mov rax, {}", token.lexeme);
|
emit!(&mut self.output, " mov rax, {}", token.lexeme);
|
||||||
}
|
}
|
||||||
TokenType::FloatLiteral => {
|
TokenType::FloatLiteral => {
|
||||||
emit!(
|
let value: f64 = token.lexeme.parse().unwrap();
|
||||||
&mut self.output,
|
emit!(&mut self.output, " mov rax, {}", value.to_bits());
|
||||||
" mov rax, __float64__({})",
|
|
||||||
token.lexeme
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
TokenType::CharLiteral => {
|
TokenType::CharLiteral => {
|
||||||
emit!(
|
emit!(
|
||||||
@@ -635,10 +643,10 @@ _builtin_environ:
|
|||||||
.chain(std::iter::once("0".into()))
|
.chain(std::iter::once("0".into()))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(",");
|
.join(",");
|
||||||
emit!(&mut self.data_section, " {} db {}", label, charcodes);
|
emit!(&mut self.data_section, " {}: .byte {}", label, charcodes);
|
||||||
self.data_counter += 1;
|
self.data_counter += 1;
|
||||||
|
|
||||||
emit!(&mut self.output, " mov rax, {}", label);
|
emit!(&mut self.output, " lea rax, [rip + {}]", label);
|
||||||
}
|
}
|
||||||
TokenType::True => {
|
TokenType::True => {
|
||||||
emit!(&mut self.output, " mov rax, 1");
|
emit!(&mut self.output, " mov rax, 1");
|
||||||
@@ -679,7 +687,7 @@ _builtin_environ:
|
|||||||
let var = env.get_var(&name.lexeme).unwrap();
|
let var = env.get_var(&name.lexeme).unwrap();
|
||||||
emit!(
|
emit!(
|
||||||
&mut self.output,
|
&mut self.output,
|
||||||
" mov rax, QWORD [rbp-{}]",
|
" mov rax, QWORD PTR [rbp-{}]",
|
||||||
var.stack_offset,
|
var.stack_offset,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -767,12 +775,12 @@ _builtin_environ:
|
|||||||
self.compile_expr(env, index)?;
|
self.compile_expr(env, index)?;
|
||||||
emit!(&mut self.output, " pop rbx");
|
emit!(&mut self.output, " pop rbx");
|
||||||
emit!(&mut self.output, " add rax, rbx");
|
emit!(&mut self.output, " add rax, rbx");
|
||||||
emit!(&mut self.output, " movzx rax, BYTE [rax]");
|
emit!(&mut self.output, " movzx rax, BYTE PTR [rax]");
|
||||||
}
|
}
|
||||||
ExprKind::AddrOf { op, expr } => match &expr.kind {
|
ExprKind::AddrOf { op, expr } => match &expr.kind {
|
||||||
ExprKind::Variable(name) => {
|
ExprKind::Variable(name) => {
|
||||||
if self.symbol_table.functions.contains_key(&name.lexeme) {
|
if self.symbol_table.functions.contains_key(&name.lexeme) {
|
||||||
emit!(&mut self.output, " mov rax, {}", name.lexeme);
|
emit!(&mut self.output, " lea rax, [rip + {}]", name.lexeme);
|
||||||
} else {
|
} else {
|
||||||
let var = match env.get_var(&name.lexeme) {
|
let var = match env.get_var(&name.lexeme) {
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
@@ -785,7 +793,7 @@ _builtin_environ:
|
|||||||
};
|
};
|
||||||
emit!(
|
emit!(
|
||||||
&mut self.output,
|
&mut self.output,
|
||||||
" lea rax, QWORD [rbp-{}]",
|
" lea rax, QWORD PTR [rbp-{}]",
|
||||||
var.stack_offset,
|
var.stack_offset,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -821,7 +829,7 @@ _builtin_environ:
|
|||||||
ExprKind::MemberAccess { left, field } => {
|
ExprKind::MemberAccess { left, field } => {
|
||||||
let offset = self.get_field_offset(left, field)?;
|
let offset = self.get_field_offset(left, field)?;
|
||||||
self.compile_expr(env, left)?;
|
self.compile_expr(env, left)?;
|
||||||
emit!(&mut self.output, " mov rax, QWORD [rax+{}]", offset);
|
emit!(&mut self.output, " mov rax, QWORD PTR [rax+{}]", offset);
|
||||||
}
|
}
|
||||||
ExprKind::Cast { expr, type_name: _ } => {
|
ExprKind::Cast { expr, type_name: _ } => {
|
||||||
self.compile_expr(env, expr)?;
|
self.compile_expr(env, expr)?;
|
||||||
@@ -857,7 +865,11 @@ _builtin_environ:
|
|||||||
let mut int_idx = 0;
|
let mut int_idx = 0;
|
||||||
for (i, arg_type) in arg_types.iter().enumerate().take(to_register) {
|
for (i, arg_type) in arg_types.iter().enumerate().take(to_register) {
|
||||||
let offset = 8 * (arg_count - 1 - i);
|
let offset = 8 * (arg_count - 1 - i);
|
||||||
emit!(&mut self.output, " mov rax, QWORD [rsp + {}]", offset);
|
emit!(
|
||||||
|
&mut self.output,
|
||||||
|
" mov rax, QWORD PTR [rsp + {}]",
|
||||||
|
offset
|
||||||
|
);
|
||||||
if arg_type == "f64" {
|
if arg_type == "f64" {
|
||||||
emit!(&mut self.output, " movq xmm{}, rax", fp_idx);
|
emit!(&mut self.output, " movq xmm{}, rax", fp_idx);
|
||||||
fp_idx += 1;
|
fp_idx += 1;
|
||||||
@@ -875,7 +887,7 @@ _builtin_environ:
|
|||||||
let offset = 8 * (arg_count - 1 - arg_idx);
|
let offset = 8 * (arg_count - 1 - arg_idx);
|
||||||
emit!(
|
emit!(
|
||||||
&mut self.output,
|
&mut self.output,
|
||||||
" mov rax, QWORD [rsp + {}]",
|
" mov rax, QWORD PTR [rsp + {}]",
|
||||||
offset + 8 * i
|
offset + 8 * i
|
||||||
);
|
);
|
||||||
emit!(&mut self.output, " push rax");
|
emit!(&mut self.output, " push rax");
|
||||||
|
|||||||
@@ -38,8 +38,7 @@ fn compile_file(args: Args) -> Result<(), ZernError> {
|
|||||||
typechecker.typecheck_stmt(&mut typechecker::Env::new(), stmt)?;
|
typechecker.typecheck_stmt(&mut typechecker::Env::new(), stmt)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut codegen =
|
let mut codegen = codegen_x86_64::CodegenX86_64::new(&symbol_table, &typechecker.expr_types);
|
||||||
codegen_x86_64::CodegenX86_64::new(&symbol_table, &typechecker.expr_types, args.emit_debug);
|
|
||||||
codegen.emit_prologue(args.use_crt)?;
|
codegen.emit_prologue(args.use_crt)?;
|
||||||
for stmt in statements {
|
for stmt in statements {
|
||||||
codegen.compile_stmt(&mut codegen_x86_64::Env::new(), &stmt)?;
|
codegen.compile_stmt(&mut codegen_x86_64::Env::new(), &stmt)?;
|
||||||
@@ -50,7 +49,9 @@ fn compile_file(args: Args) -> Result<(), ZernError> {
|
|||||||
|
|
||||||
fs::write(format!("{out}.s"), codegen.get_output()).unwrap();
|
fs::write(format!("{out}.s"), codegen.get_output()).unwrap();
|
||||||
|
|
||||||
run_command(format!("nasm -f elf64 -o {out}.o {out}.s"));
|
let debug_flag = if args.emit_debug { "-g" } else { "" };
|
||||||
|
|
||||||
|
run_command(format!("as --64 {debug_flag} -o {out}.o {out}.s"));
|
||||||
|
|
||||||
if args.use_crt {
|
if args.use_crt {
|
||||||
run_command(format!(
|
run_command(format!(
|
||||||
|
|||||||
@@ -77,10 +77,6 @@ pub enum Stmt {
|
|||||||
name: Token,
|
name: Token,
|
||||||
fields: Vec<Param>,
|
fields: Vec<Param>,
|
||||||
},
|
},
|
||||||
Enum {
|
|
||||||
name: Token,
|
|
||||||
variants: Vec<Token>,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static NEXT_EXPR_ID: AtomicUsize = AtomicUsize::new(0);
|
pub static NEXT_EXPR_ID: AtomicUsize = AtomicUsize::new(0);
|
||||||
@@ -195,9 +191,6 @@ impl Parser {
|
|||||||
if self.match_token(&[TokenType::KeywordStruct]) {
|
if self.match_token(&[TokenType::KeywordStruct]) {
|
||||||
return self.struct_declaration();
|
return self.struct_declaration();
|
||||||
}
|
}
|
||||||
if self.match_token(&[TokenType::KeywordEnum]) {
|
|
||||||
return self.enum_declaration();
|
|
||||||
}
|
|
||||||
return error!(
|
return error!(
|
||||||
self.peek().loc,
|
self.peek().loc,
|
||||||
"statements not allowed outside function body"
|
"statements not allowed outside function body"
|
||||||
@@ -281,21 +274,6 @@ impl Parser {
|
|||||||
Ok(Stmt::Struct { name, fields })
|
Ok(Stmt::Struct { name, fields })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enum_declaration(&mut self) -> Result<Stmt, ZernError> {
|
|
||||||
let name = self.consume(TokenType::Identifier, "expected enum name")?;
|
|
||||||
|
|
||||||
self.consume(TokenType::Indent, "expected indent after enum name")?;
|
|
||||||
|
|
||||||
let mut variants = vec![];
|
|
||||||
while !self.eof() && !self.check(&TokenType::Dedent) {
|
|
||||||
variants.push(self.consume(TokenType::Identifier, "expected variant name")?);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.consume(TokenType::Dedent, "expected dedent after enum variants")?;
|
|
||||||
|
|
||||||
Ok(Stmt::Enum { name, variants })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn const_declaration(&mut self) -> Result<Stmt, ZernError> {
|
fn const_declaration(&mut self) -> Result<Stmt, ZernError> {
|
||||||
let name = self.consume(TokenType::Identifier, "expected const name")?;
|
let name = self.consume(TokenType::Identifier, "expected const name")?;
|
||||||
self.consume(TokenType::Equal, "expected '=' after const name")?;
|
self.consume(TokenType::Equal, "expected '=' after const name")?;
|
||||||
|
|||||||
@@ -75,8 +75,6 @@ impl SymbolTable {
|
|||||||
}
|
}
|
||||||
let mut value = if value.lexeme.starts_with("0x") {
|
let mut value = if value.lexeme.starts_with("0x") {
|
||||||
u64::from_str_radix(&value.lexeme[2..], 16).unwrap()
|
u64::from_str_radix(&value.lexeme[2..], 16).unwrap()
|
||||||
} else if value.lexeme.starts_with("0o") {
|
|
||||||
u64::from_str_radix(&value.lexeme[2..], 8).unwrap()
|
|
||||||
} else {
|
} else {
|
||||||
value.lexeme.parse().unwrap()
|
value.lexeme.parse().unwrap()
|
||||||
} as i64;
|
} as i64;
|
||||||
@@ -146,16 +144,6 @@ impl SymbolTable {
|
|||||||
|
|
||||||
self.structs.insert(name.lexeme.clone(), fields_map);
|
self.structs.insert(name.lexeme.clone(), fields_map);
|
||||||
}
|
}
|
||||||
Stmt::Enum { name, variants } => {
|
|
||||||
// TODO: distinct enum types
|
|
||||||
for (i, v) in variants.iter().enumerate() {
|
|
||||||
let variant = format!("{}.{}", name.lexeme, v.lexeme);
|
|
||||||
if self.is_name_defined(&variant) {
|
|
||||||
return error!(name.loc, format!("tried to redefine '{}'", variant));
|
|
||||||
}
|
|
||||||
self.constants.insert(variant, i as i64);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ pub enum TokenType {
|
|||||||
KeywordStruct,
|
KeywordStruct,
|
||||||
KeywordNew,
|
KeywordNew,
|
||||||
KeywordAs,
|
KeywordAs,
|
||||||
KeywordEnum,
|
|
||||||
|
|
||||||
Indent,
|
Indent,
|
||||||
Dedent,
|
Dedent,
|
||||||
@@ -345,10 +344,6 @@ impl Tokenizer {
|
|||||||
while self.peek().is_ascii_hexdigit() {
|
while self.peek().is_ascii_hexdigit() {
|
||||||
self.advance();
|
self.advance();
|
||||||
}
|
}
|
||||||
} else if self.match_char('o') {
|
|
||||||
while matches!(self.peek(), '0'..='7') {
|
|
||||||
self.advance();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
while self.peek().is_ascii_digit() {
|
while self.peek().is_ascii_digit() {
|
||||||
self.advance();
|
self.advance();
|
||||||
@@ -399,7 +394,6 @@ impl Tokenizer {
|
|||||||
"struct" => TokenType::KeywordStruct,
|
"struct" => TokenType::KeywordStruct,
|
||||||
"new" => TokenType::KeywordNew,
|
"new" => TokenType::KeywordNew,
|
||||||
"as" => TokenType::KeywordAs,
|
"as" => TokenType::KeywordAs,
|
||||||
"enum" => TokenType::KeywordEnum,
|
|
||||||
"true" => TokenType::True,
|
"true" => TokenType::True,
|
||||||
"false" => TokenType::False,
|
"false" => TokenType::False,
|
||||||
_ => TokenType::Identifier,
|
_ => TokenType::Identifier,
|
||||||
@@ -412,7 +406,7 @@ impl Tokenizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.peek() != '"' {
|
if self.peek() != '"' {
|
||||||
return error!(self.loc, "expected '#' after 'include '");
|
return error!(self.loc, "expected '\"' after 'include '");
|
||||||
}
|
}
|
||||||
self.advance();
|
self.advance();
|
||||||
|
|
||||||
@@ -422,7 +416,7 @@ impl Tokenizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.eof() {
|
if self.eof() {
|
||||||
return error!(self.loc, "unterminated string after 'include'");
|
return error!(self.loc, "unterminated string after 'include '");
|
||||||
}
|
}
|
||||||
|
|
||||||
let path: String = self.source[path_start..self.current].iter().collect();
|
let path: String = self.source[path_start..self.current].iter().collect();
|
||||||
|
|||||||
@@ -361,7 +361,6 @@ impl<'a> TypeChecker<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Stmt::Enum { .. } => {}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,4 @@
|
|||||||
const STDIN = 0
|
include "std/posix.zr"
|
||||||
const STDOUT = 1
|
|
||||||
|
|
||||||
const SIGABRT = 6
|
|
||||||
|
|
||||||
const AT_FDCWD = -100
|
|
||||||
|
|
||||||
const S_IFDIR = 0o040000
|
|
||||||
const S_IFMT = 0o170000
|
|
||||||
|
|
||||||
const PROT_READ = 1
|
|
||||||
const PROT_WRITE = 2
|
|
||||||
|
|
||||||
const MAP_PRIVATE = 2
|
|
||||||
const MAP_ANONYMOUS = 32
|
|
||||||
|
|
||||||
const O_RDONLY = 0
|
|
||||||
const O_WRONLY = 1
|
|
||||||
const O_CREAT = 64
|
|
||||||
const O_TRUNC = 512
|
|
||||||
|
|
||||||
const SEEK_SET = 0
|
|
||||||
const SEEK_END = 2
|
|
||||||
|
|
||||||
const F_OK = 0
|
|
||||||
|
|
||||||
const SYS_read = 0
|
const SYS_read = 0
|
||||||
const SYS_write = 1
|
const SYS_write = 1
|
||||||
27
std/posix.zr
Normal file
27
std/posix.zr
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
const STDIN_FILENO = 0
|
||||||
|
const STDOUT_FILENO = 1
|
||||||
|
|
||||||
|
const SIGABRT = 6
|
||||||
|
|
||||||
|
const AT_FDCWD = -100
|
||||||
|
|
||||||
|
const S_IFDIR = 16384
|
||||||
|
const S_IFMT = 61440
|
||||||
|
|
||||||
|
const PROT_READ = 1
|
||||||
|
const PROT_WRITE = 2
|
||||||
|
|
||||||
|
const MAP_PRIVATE = 2
|
||||||
|
const MAP_ANONYMOUS = 32
|
||||||
|
|
||||||
|
const O_RDONLY = 0
|
||||||
|
const O_WRONLY = 1
|
||||||
|
const O_CREAT = 64
|
||||||
|
const O_TRUNC = 512
|
||||||
|
|
||||||
|
const SEEK_SET = 0
|
||||||
|
const SEEK_END = 2
|
||||||
|
|
||||||
|
const F_OK = 0
|
||||||
|
|
||||||
|
const CLOCK_REALTIME = 0
|
||||||
35
std/std.zr
35
std/std.zr
@@ -1,4 +1,4 @@
|
|||||||
include "std/linux_constants.zr"
|
include "std/linux.zr"
|
||||||
|
|
||||||
func panic[msg: str] : void
|
func panic[msg: str] : void
|
||||||
io.print("PANIC: ")
|
io.print("PANIC: ")
|
||||||
@@ -265,7 +265,7 @@ func io.printf[..] : void
|
|||||||
s += 1
|
s += 1
|
||||||
|
|
||||||
func io.print_sized[x: ptr, size: i64] : void
|
func io.print_sized[x: ptr, size: i64] : void
|
||||||
_builtin_syscall(SYS_write, STDOUT, x, size)
|
_builtin_syscall(SYS_write, STDOUT_FILENO, x, size)
|
||||||
|
|
||||||
func io.print[x: str] : void
|
func io.print[x: str] : void
|
||||||
io.print_sized(x as ptr, x->len())
|
io.print_sized(x as ptr, x->len())
|
||||||
@@ -381,7 +381,7 @@ func f64.to_str_buf[x: i64, buf: ptr] : void
|
|||||||
|
|
||||||
func io.read_char[] : u8
|
func io.read_char[] : u8
|
||||||
c := 0 as u8
|
c := 0 as u8
|
||||||
_builtin_syscall(SYS_read, STDIN, ^c, 1)
|
_builtin_syscall(SYS_read, STDIN_FILENO, ^c, 1)
|
||||||
return c
|
return c
|
||||||
|
|
||||||
func io.read_line[] : str
|
func io.read_line[] : str
|
||||||
@@ -438,7 +438,7 @@ func io.write_file[path: str, content: str] : bool
|
|||||||
return io.write_binary_file(path, content as ptr, content->len())
|
return io.write_binary_file(path, content as ptr, content->len())
|
||||||
|
|
||||||
func io.write_binary_file[path: str, content: ptr, size: i64] : bool
|
func io.write_binary_file[path: str, content: ptr, size: i64] : bool
|
||||||
fd := _builtin_syscall(SYS_openat, AT_FDCWD, path, O_WRONLY|O_CREAT|O_TRUNC, 0o644)
|
fd := _builtin_syscall(SYS_openat, AT_FDCWD, path, O_WRONLY|O_CREAT|O_TRUNC, math.octal_to_decimal(644))
|
||||||
if fd < 0
|
if fd < 0
|
||||||
return false
|
return false
|
||||||
|
|
||||||
@@ -901,6 +901,17 @@ func math.pow[b: i64, e: i64] : i64
|
|||||||
func math.lcm[a: i64, b: i64] : i64
|
func math.lcm[a: i64, b: i64] : i64
|
||||||
return (a / math.gcd(a, b)) * b
|
return (a / math.gcd(a, b)) * b
|
||||||
|
|
||||||
|
func math.octal_to_decimal[octal: i64] : i64
|
||||||
|
decimal := 0
|
||||||
|
base := 1
|
||||||
|
|
||||||
|
while octal > 0
|
||||||
|
digit := octal % 10
|
||||||
|
decimal += digit * base
|
||||||
|
base = base * 8
|
||||||
|
octal = octal / 10
|
||||||
|
return decimal
|
||||||
|
|
||||||
struct Blob
|
struct Blob
|
||||||
data: ptr
|
data: ptr
|
||||||
size: i64
|
size: i64
|
||||||
@@ -1146,6 +1157,12 @@ func os.sleep[ms: i64] : void
|
|||||||
req->tv_nsec = (ms % 1000) * 1000000
|
req->tv_nsec = (ms % 1000) * 1000000
|
||||||
_builtin_syscall(SYS_nanosleep, req, 0)
|
_builtin_syscall(SYS_nanosleep, req, 0)
|
||||||
|
|
||||||
|
func os.time[] : i64
|
||||||
|
ts := new os.Timespec
|
||||||
|
_builtin_syscall(SYS_clock_gettime, CLOCK_REALTIME, ts)
|
||||||
|
out := ts->tv_sec * 1000 + ts->tv_nsec / 1000000
|
||||||
|
return out
|
||||||
|
|
||||||
func os.urandom_buf[buf: ptr, n: i64] : void
|
func os.urandom_buf[buf: ptr, n: i64] : void
|
||||||
pos := 0
|
pos := 0
|
||||||
while pos < n
|
while pos < n
|
||||||
@@ -1164,16 +1181,6 @@ func os.urandom_i64[] : i64
|
|||||||
os.urandom_buf(^n, 8)
|
os.urandom_buf(^n, 8)
|
||||||
return n
|
return n
|
||||||
|
|
||||||
struct os.Timeval
|
|
||||||
tv_sec: i64
|
|
||||||
tv_usec: i64
|
|
||||||
|
|
||||||
func os.time[] : i64
|
|
||||||
tv := new os.Timeval
|
|
||||||
_builtin_syscall(SYS_gettimeofday, tv, 0)
|
|
||||||
out := tv->tv_sec * 1000 + tv->tv_usec / 1000
|
|
||||||
return out
|
|
||||||
|
|
||||||
func os.run_shell_command[command: str] : i64, bool
|
func os.run_shell_command[command: str] : i64, bool
|
||||||
pid := _builtin_syscall(SYS_fork)
|
pid := _builtin_syscall(SYS_fork)
|
||||||
if pid < 0
|
if pid < 0
|
||||||
|
|||||||
Reference in New Issue
Block a user