_var_arg
This commit is contained in:
@@ -151,21 +151,6 @@ _builtin_syscall:
|
||||
mov r9, [rsp+8]
|
||||
syscall
|
||||
ret
|
||||
|
||||
section .text.io.printf
|
||||
io.printf:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
sub rsp, 48
|
||||
mov [rsp], rsi
|
||||
mov [rsp + 8], rdx
|
||||
mov [rsp + 16], rcx
|
||||
mov [rsp + 24], r8
|
||||
mov [rsp + 32], r9
|
||||
lea rsi, [rsp]
|
||||
call io._printf_impl
|
||||
leave
|
||||
ret
|
||||
"
|
||||
);
|
||||
|
||||
@@ -337,7 +322,16 @@ _builtin_environ:
|
||||
}
|
||||
}
|
||||
}
|
||||
Params::Variadic(_name) => todo!(),
|
||||
Params::Variadic => {
|
||||
emit!(&mut self.output, " sub rsp, 48");
|
||||
emit!(&mut self.output, " mov [rbp - 8], rdi");
|
||||
emit!(&mut self.output, " mov [rbp - 16], rsi");
|
||||
emit!(&mut self.output, " mov [rbp - 24], rdx");
|
||||
emit!(&mut self.output, " mov [rbp - 32], rcx");
|
||||
emit!(&mut self.output, " mov [rbp - 40], r8");
|
||||
emit!(&mut self.output, " mov [rbp - 48], r9");
|
||||
env.next_offset += 48;
|
||||
}
|
||||
}
|
||||
|
||||
self.compile_stmt(env, body)?;
|
||||
@@ -626,6 +620,12 @@ _builtin_environ:
|
||||
paren: _,
|
||||
args,
|
||||
} => {
|
||||
if let Expr::Variable(callee_name) = &**callee
|
||||
&& callee_name.lexeme == "_var_arg"
|
||||
{
|
||||
return self.emit_var_arg(env, &args[0]);
|
||||
}
|
||||
|
||||
for arg in args {
|
||||
self.compile_expr(env, arg)?;
|
||||
emit!(&mut self.output, " push rax");
|
||||
@@ -795,4 +795,33 @@ _builtin_environ:
|
||||
|
||||
Ok(field.offset)
|
||||
}
|
||||
|
||||
fn emit_var_arg(&mut self, env: &mut Env, index_expr: &Expr) -> Result<(), ZernError> {
|
||||
self.compile_expr(env, index_expr)?;
|
||||
emit!(&mut self.output, " mov r10, rax");
|
||||
|
||||
let stack_label = self.label();
|
||||
let done_label = self.label();
|
||||
|
||||
emit!(&mut self.output, " cmp r10, 6");
|
||||
emit!(&mut self.output, " jge {}", stack_label);
|
||||
|
||||
// < 6
|
||||
emit!(&mut self.output, " mov rax, r10");
|
||||
emit!(&mut self.output, " inc rax");
|
||||
emit!(&mut self.output, " shl rax, 3");
|
||||
emit!(&mut self.output, " neg rax");
|
||||
emit!(&mut self.output, " mov rax, [rbp + rax]");
|
||||
emit!(&mut self.output, " jmp {}", done_label);
|
||||
|
||||
// >= 6
|
||||
emit!(&mut self.output, "{}:", stack_label);
|
||||
emit!(&mut self.output, " mov rax, r10");
|
||||
emit!(&mut self.output, " sub rax, 6");
|
||||
emit!(&mut self.output, " shl rax, 3");
|
||||
emit!(&mut self.output, " mov rax, [rbp + 16 + rax]");
|
||||
|
||||
emit!(&mut self.output, "{}:", done_label);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ pub struct Param {
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Params {
|
||||
Normal(Vec<Param>),
|
||||
Variadic(Token),
|
||||
Variadic,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -170,12 +170,11 @@ impl Parser {
|
||||
let name = self.consume(TokenType::Identifier, "expected function name")?;
|
||||
self.consume(TokenType::LeftBracket, "expected '[' after function name")?;
|
||||
|
||||
let mut variadic_param: Option<Token> = None;
|
||||
let mut is_variadic = false;
|
||||
let mut params = vec![];
|
||||
if !self.check(&TokenType::RightBracket) {
|
||||
if self.match_token(&[TokenType::DoubleDot]) {
|
||||
variadic_param =
|
||||
Some(self.consume(TokenType::Identifier, "expected variadic parameter name")?);
|
||||
is_variadic = true;
|
||||
} else {
|
||||
loop {
|
||||
let var_name =
|
||||
@@ -201,13 +200,13 @@ impl Parser {
|
||||
let body = Box::new(self.block()?);
|
||||
self.is_inside_function = false;
|
||||
|
||||
let params = match variadic_param {
|
||||
Some(name) => Params::Variadic(name),
|
||||
None => Params::Normal(params),
|
||||
};
|
||||
Ok(Stmt::Function {
|
||||
name,
|
||||
params,
|
||||
params: if is_variadic {
|
||||
Params::Variadic
|
||||
} else {
|
||||
Params::Normal(params)
|
||||
},
|
||||
return_type,
|
||||
body,
|
||||
exported,
|
||||
|
||||
@@ -264,24 +264,26 @@ func mem.write16be[x: ptr, d: i64] : void
|
||||
func mem.write64[x: ptr, d: any] : void
|
||||
_builtin_set64(x, d)
|
||||
|
||||
// see emit_prologue for the io.printf wrapper
|
||||
func io._printf_impl[s: ptr, args: ptr] : void
|
||||
func io.printf[..] : void
|
||||
let s: ptr = _var_arg(0) as ptr
|
||||
let i: i64 = 1
|
||||
|
||||
while s[0]
|
||||
if s[0] == '%'
|
||||
s = s + 1
|
||||
|
||||
if s[0] == 'd'
|
||||
io.print_i64(mem.read64(args))
|
||||
args = args + 8
|
||||
io.print_i64(_var_arg(i))
|
||||
i = i + 1
|
||||
else if s[0] == 'x'
|
||||
io.print_i64_hex(mem.read64(args))
|
||||
args = args + 8
|
||||
io.print_i64_hex(_var_arg(i))
|
||||
i = i + 1
|
||||
else if s[0] == 's'
|
||||
io.print(mem.read64(args) as str)
|
||||
args = args + 8
|
||||
io.print(_var_arg(i) as str)
|
||||
i = i + 1
|
||||
else if s[0] == 'c'
|
||||
io.print_char(mem.read64(args) as u8)
|
||||
args = args + 8
|
||||
io.print_char(_var_arg(i) as u8)
|
||||
i = i + 1
|
||||
else if s[0] == '%'
|
||||
io.print_char('%')
|
||||
else if s[0] == 0
|
||||
|
||||
@@ -54,8 +54,8 @@ impl SymbolTable {
|
||||
FnType::new("void", vec!["ptr", "i64"]),
|
||||
),
|
||||
("_builtin_syscall".into(), FnType::new_variadic("i64")),
|
||||
("io.printf".into(), FnType::new_variadic("void")),
|
||||
("_builtin_environ".into(), FnType::new("ptr", vec![])),
|
||||
("_var_arg".into(), FnType::new("any", vec!["i64"])),
|
||||
]),
|
||||
constants: HashMap::new(),
|
||||
structs: HashMap::new(),
|
||||
@@ -110,7 +110,7 @@ impl SymbolTable {
|
||||
),
|
||||
},
|
||||
),
|
||||
Params::Variadic(name) => self.functions.insert(
|
||||
Params::Variadic => self.functions.insert(
|
||||
name.lexeme.clone(),
|
||||
FnType {
|
||||
return_type: return_type.lexeme.clone(),
|
||||
|
||||
@@ -195,7 +195,7 @@ impl<'a> TypeChecker<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
Params::Variadic(_) => {
|
||||
Params::Variadic => {
|
||||
return error!(&name.loc, "main function cannot be variadic");
|
||||
}
|
||||
}
|
||||
@@ -228,9 +228,7 @@ impl<'a> TypeChecker<'a> {
|
||||
);
|
||||
}
|
||||
}
|
||||
Params::Variadic(name) => {
|
||||
env.define_var(name.lexeme.clone(), "ptr".into());
|
||||
}
|
||||
Params::Variadic => {}
|
||||
}
|
||||
|
||||
self.typecheck_stmt(env, body)?;
|
||||
|
||||
Reference in New Issue
Block a user