Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 5 additions & 8 deletions libb/6502.b
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
__operator__(/, _div);
__operator__(%, _rem);

exit(code) {
0(code);
}
Expand Down Expand Up @@ -33,12 +36,6 @@ realloc(ptr, size) {
return (malloc(size));
}

/* TODO: Try to implement this function with assembly
Problem with this implementation is that it is not
mapped to the operator
We cannot call this function `div` as it conflicts
with the `divmod` test
*/
_div(a, b) {
auto d;
d = 0; while(a >= b) {
Expand Down Expand Up @@ -67,9 +64,9 @@ printn(n, b, sign) {
n = -n;
}

if(a=_div(n, b)) /* assignment, not test for equality */
if(a=n/b) /* assignment, not test for equality */
printn(a, b, 0); /* recursive */
c = _rem(n,b) + '0';
c = n%b + '0';
if (c > '9') c += 7;
putchar(c);
}
Expand Down
43 changes: 42 additions & 1 deletion src/b.rs
Original file line number Diff line number Diff line change
Expand Up @@ -870,7 +870,7 @@ pub unsafe fn compile_statement(l: *mut Lexer, c: *mut Compiler) -> Option<()> {
label: (*switch_frame).label
}, case_loc, c);

push_opcode(Op::Binop{
push_opcode(Op::Binop {
binop: Binop::Equal,
index: (*switch_frame).cond,
lhs: (*switch_frame).value,
Expand Down Expand Up @@ -998,6 +998,7 @@ pub struct Compiler {
pub data: Array<u8>,
pub extrns: Array<*const c_char>,
pub variadics: Array<(*const c_char, Variadic)>,
pub op_overloads: Array<(Binop, *const c_char)>,
pub globals: Array<Global>,
pub asm_funcs: Array<AsmFunc>,
/// Arena into which the Compiler allocates all the names and
Expand Down Expand Up @@ -1064,6 +1065,26 @@ pub unsafe fn compile_program(l: *mut Lexer, c: *mut Compiler) -> Option<()> {
get_and_expect_token_but_continue(l, c, Token::CParen)?;
get_and_expect_token_but_continue(l, c, Token::SemiColon)?;
}
Token::Operator => {
get_and_expect_token_but_continue(l, c, Token::OParen)?;
lexer::get_token(l)?;
let binop = match Binop::from_token((*l).token) {
Some(binop) => Some(binop),
None => {
diagf!((*l).loc, c!("ERROR: expected binary operator, but got %s\n"),
lexer::display_token((*l).token));
None
}
}?;
get_and_expect_token_but_continue(l, c, Token::Comma)?;
get_and_expect_token_but_continue(l, c, Token::ID)?;

let func = arena::strdup(&mut (*c).arena, (*l).string);
da_append(&mut (*c).op_overloads, (binop, func));

get_and_expect_token_but_continue(l, c, Token::CParen)?;
get_and_expect_token_but_continue(l, c, Token::SemiColon)?;
},
Token::Extrn => {
while (*l).token != Token::SemiColon {
get_and_expect_token(l, Token::ID)?;
Expand Down Expand Up @@ -1387,6 +1408,26 @@ pub unsafe fn main(mut argc: i32, mut argv: *mut*mut c_char) -> Option<()> {
}
}

// resolve operators
for i in 0..c.funcs.count {
let f = *c.funcs.items.add(i);
for j in 0..f.body.count {
let op = f.body.items.add(j);
if let Op::Binop {binop, index, lhs, rhs} = (*op).opcode {
for i in 0..c.op_overloads.count {
let (bop, fun) = *c.op_overloads.items.add(i);
if binop == bop {
let mut args: Array<Arg> = zeroed();
da_append(&mut args, lhs);
da_append(&mut args, rhs);
(*op).opcode = Op::Funcall {result: index, fun: Arg::External(fun), args};
break;
}
}
}
}
}

scope_pop(&mut c.vars); // end global scope

if c.error_count > 0 {
Expand Down
32 changes: 6 additions & 26 deletions src/codegen/mos6502.rs
Original file line number Diff line number Diff line change
Expand Up @@ -924,32 +924,12 @@ pub unsafe fn generate_function(name: *const c_char, params_count: usize, auto_v
instr(out, TXA);
},
Binop::Mod => {
// !! TODO !! this should be implemented here and not as a B functions.
// TODO: current mod implementation is linear, we can do better.
load_arg(rhs, op.loc, out, asm);
push16(out, asm);
load_arg(lhs, op.loc, out, asm);

instr0(out, JSR, ABS);
add_reloc(out, RelocationKind::External{name: c!("_rem"), offset: 0,
byte: Byte::Both}, asm);
instr(out, TAX);
pop16_discard(out, asm);
instr(out, TXA);
diagf!(op.loc, c!("FATAL: tried to use Mod operation, define using __operator__ instead\n"));
abort();
},
Binop::Div => {
// !! TODO !! this should be implemented here and not as a B functions.
// TODO: current div implementation is linear, we can do better.
load_arg(rhs, op.loc, out, asm);
push16(out, asm);
load_arg(lhs, op.loc, out, asm);

instr0(out, JSR, ABS);
add_reloc(out, RelocationKind::External{name: c!("_div"), offset: 0,
byte: Byte::Both}, asm);
instr(out, TAX);
pop16_discard(out, asm);
instr(out, TXA);
diagf!(op.loc, c!("FATAL: tried to use Div operation, define using __operator__ instead\n"));
abort();
},
Binop::Mult => {
load_two_args(out, lhs, rhs, op, asm);
Expand Down Expand Up @@ -1313,7 +1293,7 @@ pub unsafe fn apply_relocations(out: *mut String_Builder, data_start: u16, asm:
}
}
printf(c!("linking failed. could not find label `%s.%u'\n"), name, label);
unreachable!();
abort();
},
RelocationKind::External{name, offset, byte} => {
for i in 0..(*asm).externals.count {
Expand All @@ -1329,7 +1309,7 @@ pub unsafe fn apply_relocations(out: *mut String_Builder, data_start: u16, asm:
}
}
printf(c!("linking failed. could not find extern `%s'\n"), name);
unreachable!();
abort();
},
RelocationKind::AddressRel{idx} => {
let jaddr = *(*asm).addresses.items.add(idx);
Expand Down
3 changes: 3 additions & 0 deletions src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ pub enum Token {
Return,
Asm,
Variadic,
Operator,
}

pub unsafe fn display_token(token: Token) -> *const c_char {
Expand Down Expand Up @@ -160,6 +161,7 @@ pub unsafe fn display_token(token: Token) -> *const c_char {
// TODO: document all this magical extension keywords somewhere
Token::Asm => c!("keyword `__asm__`"),
Token::Variadic => c!("keyword `__variadic__`"),
Token::Operator => c!("keyword `__operator__`"),
}
}

Expand Down Expand Up @@ -264,6 +266,7 @@ const KEYWORDS: *const [(*const c_char, Token)] = &[
(c!("return"), Token::Return),
(c!("__asm__"), Token::Asm),
(c!("__variadic__"), Token::Variadic),
(c!("__operator__"), Token::Operator),
];

#[derive(Clone, Copy)]
Expand Down
48 changes: 48 additions & 0 deletions tests.json
Original file line number Diff line number Diff line change
Expand Up @@ -1878,5 +1878,53 @@
"state": "Enabled",
"comment": ""
}
},
"operator_overloading": {
"6502": {
"expected_stdout": "1: 2 * 3\r\n2: 5 + 4\r\n3: 1 - 5\r\nresult = 11\r\nTesting B++\n",
"state": "Enabled",
"comment": ""
},
"gas-x86_64-windows": {
"expected_stdout": "1: 2 * 3\r\n2: 5 + 4\r\n3: 1 - 5\r\nresult = 11\r\nTesting B++\r\n",
"state": "Enabled",
"comment": ""
},
"gas-x86_64-linux": {
"expected_stdout": "1: 2 * 3\n2: 5 + 4\n3: 1 - 5\nresult = 11\nTesting B++\n",
"state": "Enabled",
"comment": ""
}
"gas-x86_64-darwin": {
"expected_stdout": "1: 2 * 3\n2: 5 + 4\n3: 1 - 5\nresult = 11\nTesting B++\n",
"state": "Enabled",
"comment": ""
},
"gas-aarch64-linux": {
"expected_stdout": "1: 2 * 3\n2: 5 + 4\n3: 1 - 5\nresult = 11\nTesting B++\n",
"state": "Enabled",
"comment": ""
},
"gas-aarch64-darwin": {
"expected_stdout": "1: 2 * 3\n2: 5 + 4\n3: 1 - 5\nresult = 11\nTesting B++\n",
"state": "Enabled",
"comment": ""
},
"uxn": {
"expected_stdout": "1: 2 * 3\n2: 5 + 4\n3: 1 - 5\nresult = 11\nTesting B++\n",
"state": "Enabled",
"comment": ""
},
"fasm-x86_64-windows": {
"expected_stdout": "1: 2 * 3\r\n2: 5 + 4\r\n3: 1 - 5\r\nresult = 11\r\nTesting B++\r\n",
"state": "Enabled",
"comment": ""
},
"fasm-x86_64-linux": {
"expected_stdout": "1: 2 * 3\n2: 5 + 4\n3: 1 - 5\nresult = 11\nTesting B++\n",
"state": "Enabled",
"comment": ""
}

}
}
30 changes: 30 additions & 0 deletions tests/operator_overloading.b
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
f1(a, b) {
printf("1: %d * %d\n", a, b);
return (a+b);
}
f2(a, b) {
printf("2: %d + %d\n", a, b);
return (a-b);
}
f3(a, b) {
printf("3: %d - %d\n", a, b);
return (b+a+b);
}

__operator__(*, f1);
__operator__(>>, f2);
__operator__(<=, f3);

__operator__(<<, f);

f(s, w) {
printf("%s", w);
return (s);
}
cout 1;
endl "\n";

main() {
printf("result = %d\n", ((2 * 3) >> 4) <= 5);
cout << "Testing B++" << endl;
}