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: 13 additions & 0 deletions docs/bext.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,19 @@ Some targets like `gas-aarch64-darwin` have a different calling convention for v
this is needed to make the compiler use the correct calling convention. \
the syntax is `__variadic__(function_name, number_of_fixed_args);`

## C-style for loops
```c
main() {
for (auto i = 2; i < 5; i++) {
printf("%lld^2 = %lld\n", i, i*i);
}

for(;;) printf("infinite loop\n");
}
```

Very useful for iterating over a range of numbers.

<!--
TODO: hex-literals and C++ style comments are currently considered deviations
and not extensions, thus disabled in historical mode, which is a bug.
Expand Down
58 changes: 58 additions & 0 deletions src/b.rs
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,64 @@ pub unsafe fn compile_statement(l: *mut Lexer, c: *mut Compiler) -> Option<()> {
push_opcode(Op::Label {label: out_label}, (*l).loc, c);
Some(())
}
Token::For => {
scope_push(&mut (*c).vars);
get_and_expect_token(l, Token::OParen)?;

let cond_label = allocate_label_index(c);
let iter_label = allocate_label_index(c);
let body_label = allocate_label_index(c);
let out_label = allocate_label_index(c);

let saved_point = (*l).parse_point;
lexer::get_token(l)?;

if (*l).token == Token::Auto {
get_and_expect_token(l, Token::ID)?;
let name = arena::strdup(&mut (*c).arena, (*l).string);
let index = allocate_auto_var(&mut (*c).auto_vars_ator);
declare_var(c, name, (*l).loc, Storage::Auto {index})?;
get_and_expect_token(l, Token::Eq)?;
let loc = (*l).loc;
let (arg, _) = compile_expression(l, c)?;
push_opcode(Op::AutoAssign {index, arg}, loc, c);
get_and_expect_token(l, Token::SemiColon)?;
} else if (*l).token != Token::SemiColon {
(*l).parse_point = saved_point;
compile_expression(l, c)?;
get_and_expect_token(l, Token::SemiColon)?;
}

push_opcode(Op::Label {label: cond_label}, (*l).loc, c);
let saved_point = (*l).parse_point;
lexer::get_token(l);
if (*l).token != Token::SemiColon {
(*l).parse_point = saved_point;
let (arg, _) = compile_expression(l, c)?;
push_opcode(Op::JmpIfNotLabel{label: out_label, arg}, (*l).loc, c);
get_and_expect_token(l, Token::SemiColon)?;
}
push_opcode(Op::JmpLabel{label: body_label}, (*l).loc, c);

push_opcode(Op::Label {label: iter_label}, (*l).loc, c);
let saved_point = (*l).parse_point;
lexer::get_token(l);
if (*l).token != Token::CParen {
(*l).parse_point = saved_point;
compile_expression(l, c)?;
get_and_expect_token(l, Token::CParen)?;
}
push_opcode(Op::JmpLabel{label: cond_label}, (*l).loc, c);


push_opcode(Op::Label {label: body_label}, (*l).loc, c);
compile_statement(l, c)?;
push_opcode(Op::JmpLabel{label: iter_label}, (*l).loc, c);
push_opcode(Op::Label {label: out_label}, (*l).loc, c);

scope_pop(&mut (*c).vars);
Some(())
}
Token::Return => {
get_and_expect_tokens(l, &[Token::SemiColon, Token::OParen])?;
if (*l).token == Token::SemiColon {
Expand Down
3 changes: 3 additions & 0 deletions src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ pub enum Token {
If,
Else,
While,
For,
Switch,
Goto,
Return,
Expand Down Expand Up @@ -153,6 +154,7 @@ pub unsafe fn display_token(token: Token) -> *const c_char {
Token::If => c!("keyword `if`"),
Token::Else => c!("keyword `else`"),
Token::While => c!("keyword `while`"),
Token::For => c!("keyword `for`"),
Token::Switch => c!("keyword `switch`"),
Token::Goto => c!("keyword `goto`"),
Token::Return => c!("keyword `return`"),
Expand Down Expand Up @@ -259,6 +261,7 @@ const KEYWORDS: *const [(*const c_char, Token)] = &[
(c!("if"), Token::If),
(c!("else"), Token::Else),
(c!("while"), Token::While),
(c!("for"), Token::For),
(c!("switch"), Token::Switch),
(c!("goto"), Token::Goto),
(c!("return"), Token::Return),
Expand Down
56 changes: 56 additions & 0 deletions tests.json
Original file line number Diff line number Diff line change
Expand Up @@ -2147,5 +2147,61 @@
"expected_stdout": "",
"state": "Disabled",
"comment": "Doesn't make sense for this target"
},
{
"case": "for_loop",
"target": "ilasm-mono",
"expected_stdout": "",
"state": "Enabled",
"comment": "Failed to build on record"
},
{
"case": "for_loop",
"target": "gas-aarch64-linux",
"expected_stdout": "i: 0\ni: 1\ni: 2\ni outside: 69\nj: 3\nj: 5\nj: 7\nx: 2\nx: 4\nx: 8\ny: 69\ny: 70\ny: 71\nz: 100\nz: 101\nz: 102\noh no!\n",
"state": "Enabled",
"comment": ""
},
{
"case": "for_loop",
"target": "gas-aarch64-darwin",
"expected_stdout": "i: 0\ni: 1\ni: 2\ni outside: 69\nj: 3\nj: 5\nj: 7\nx: 2\nx: 4\nx: 8\ny: 69\ny: 70\ny: 71\nz: 100\nz: 101\nz: 102\noh no!\n",
"state": "Enabled",
"comment": ""
},
{
"case": "for_loop",
"target": "gas-x86_64-linux",
"expected_stdout": "i: 0\ni: 1\ni: 2\ni outside: 69\nj: 3\nj: 5\nj: 7\nx: 2\nx: 4\nx: 8\ny: 69\ny: 70\ny: 71\nz: 100\nz: 101\nz: 102\noh no!\n",
"state": "Enabled",
"comment": ""
},
{
"case": "for_loop",
"target": "gas-x86_64-windows",
"expected_stdout": "i: 0\r\ni: 1\r\ni: 2\r\ni outside: 69\r\nj: 3\r\nj: 5\r\nj: 7\r\nx: 2\r\nx: 4\r\nx: 8\r\ny: 69\r\ny: 70\r\ny: 71\r\nz: 100\r\nz: 101\r\nz: 102\r\noh no!\r\n",
"state": "Enabled",
"comment": ""
},
{
"case": "for_loop",
"target": "gas-x86_64-darwin",
"expected_stdout": "i: 0\ni: 1\ni: 2\ni outside: 69\nj: 3\nj: 5\nj: 7\nx: 2\nx: 4\nx: 8\ny: 69\ny: 70\ny: 71\nz: 100\nz: 101\nz: 102\noh no!\n",
"state": "Enabled",
"comment": ""
},
{
"case": "for_loop",
"target": "6502-posix",
"expected_stdout": "i: 0\r\ni: 1\r\ni: 2\r\ni outside: 69\r\nj: 3\r\nj: 5\r\nj: 7\r\nx: 2\r\nx: 4\r\nx: 8\r\ny: 69\r\ny: 70\r\ny: 71\r\nz: 100\r\nz: 101\r\nz: 102\r\noh no!\r\n",
"state": "Enabled",
"comment": ""
},
{
"case": "for_loop",
"target": "uxn",
"expected_stdout": "i: 0\ni: 1\ni: 2\ni outside: 69\nj: 3\nj: 5\nj: 7\nx: 2\nx: 4\nx: 8\ny: 69\ny: 70\ny: 71\nz: 100\nz: 101\nz: 102\noh no!\n",
"state": "Enabled",
"comment": ""
}
]
27 changes: 27 additions & 0 deletions tests/for_loop.b
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
main() {
auto i; i = 69;
for (auto i = 0; i < 3; i++) printf("i: %lld\n", i);
printf("i outside: %lld\n", i);

auto j;
for (j = 3; j < 9; j += 2) printf("j: %lld\n", j);

auto x; x = 2;
for (;x < 10; x *= 2) printf("x: %lld\n", x);

auto y; y = 69;
for (;y <= 71;) printf("y: %lld\n", y++);

auto z; z = 100;
for (;;z++) {
printf("z: %lld\n", z);
if (z >= 102) goto out1;
}
out1:

for(;;) {
printf("oh no!\n");
goto out2;
}
out2:
}
Loading