Skip to content

Commit b4c5cd0

Browse files
committed
Add C-style for loops
1 parent 078429a commit b4c5cd0

File tree

5 files changed

+153
-0
lines changed

5 files changed

+153
-0
lines changed

docs/bext.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,19 @@ Some targets like `gas-aarch64-darwin` have a different calling convention for v
5656
this is needed to make the compiler use the correct calling convention. \
5757
the syntax is `__variadic__(function_name, number_of_fixed_args);`
5858
59+
## C-style for loops
60+
```c
61+
main() {
62+
for (auto i = 2; i < 5; i++) {
63+
printf("%lld^2 = %lld\n", i, i*i);
64+
}
65+
66+
for(;;) printf("infinite loop\n");
67+
}
68+
```
69+
70+
Very useful for iterating over a range of numbers.
71+
5972
<!--
6073
TODO: hex-literals and C++ style comments are currently considered deviations
6174
and not extensions, thus disabled in historical mode, which is a bug.

src/b.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,62 @@ pub unsafe fn compile_statement(l: *mut Lexer, c: *mut Compiler) -> Option<()> {
789789
push_opcode(Op::Label {label: out_label}, (*l).loc, c);
790790
Some(())
791791
}
792+
Token::For => {
793+
get_and_expect_token(l, Token::OParen)?;
794+
795+
let cond_label = allocate_label_index(c);
796+
let iter_label = allocate_label_index(c);
797+
let body_label = allocate_label_index(c);
798+
let out_label = allocate_label_index(c);
799+
800+
let saved_point = (*l).parse_point;
801+
lexer::get_token(l)?;
802+
803+
if (*l).token == Token::Auto {
804+
get_and_expect_token(l, Token::ID)?;
805+
let name = arena::strdup(&mut (*c).arena, (*l).string);
806+
let index = allocate_auto_var(&mut (*c).auto_vars_ator);
807+
declare_var(c, name, (*l).loc, Storage::Auto {index})?;
808+
get_and_expect_token(l, Token::Eq)?;
809+
let loc = (*l).loc;
810+
let (arg, _) = compile_expression(l, c)?;
811+
push_opcode(Op::AutoAssign {index, arg}, loc, c);
812+
get_and_expect_token(l, Token::SemiColon)?;
813+
} else if (*l).token != Token::SemiColon {
814+
(*l).parse_point = saved_point;
815+
compile_expression(l, c)?;
816+
get_and_expect_token(l, Token::SemiColon)?;
817+
}
818+
819+
push_opcode(Op::Label {label: cond_label}, (*l).loc, c);
820+
let saved_point = (*l).parse_point;
821+
lexer::get_token(l);
822+
if (*l).token != Token::SemiColon {
823+
(*l).parse_point = saved_point;
824+
let (arg, _) = compile_expression(l, c)?;
825+
push_opcode(Op::JmpIfNotLabel{label: out_label, arg}, (*l).loc, c);
826+
get_and_expect_token(l, Token::SemiColon)?;
827+
}
828+
push_opcode(Op::JmpLabel{label: body_label}, (*l).loc, c);
829+
830+
push_opcode(Op::Label {label: iter_label}, (*l).loc, c);
831+
let saved_point = (*l).parse_point;
832+
lexer::get_token(l);
833+
if (*l).token != Token::CParen {
834+
(*l).parse_point = saved_point;
835+
compile_expression(l, c)?;
836+
get_and_expect_token(l, Token::CParen)?;
837+
}
838+
push_opcode(Op::JmpLabel{label: cond_label}, (*l).loc, c);
839+
840+
841+
push_opcode(Op::Label {label: body_label}, (*l).loc, c);
842+
compile_statement(l, c)?;
843+
push_opcode(Op::JmpLabel{label: iter_label}, (*l).loc, c);
844+
push_opcode(Op::Label {label: out_label}, (*l).loc, c);
845+
846+
Some(())
847+
}
792848
Token::Return => {
793849
get_and_expect_tokens(l, &[Token::SemiColon, Token::OParen])?;
794850
if (*l).token == Token::SemiColon {

src/lexer.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ pub enum Token {
8888
If,
8989
Else,
9090
While,
91+
For,
9192
Switch,
9293
Goto,
9394
Return,
@@ -153,6 +154,7 @@ pub unsafe fn display_token(token: Token) -> *const c_char {
153154
Token::If => c!("keyword `if`"),
154155
Token::Else => c!("keyword `else`"),
155156
Token::While => c!("keyword `while`"),
157+
Token::For => c!("keyword `for`"),
156158
Token::Switch => c!("keyword `switch`"),
157159
Token::Goto => c!("keyword `goto`"),
158160
Token::Return => c!("keyword `return`"),
@@ -259,6 +261,7 @@ const KEYWORDS: *const [(*const c_char, Token)] = &[
259261
(c!("if"), Token::If),
260262
(c!("else"), Token::Else),
261263
(c!("while"), Token::While),
264+
(c!("for"), Token::For),
262265
(c!("switch"), Token::Switch),
263266
(c!("goto"), Token::Goto),
264267
(c!("return"), Token::Return),

tests.json

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2147,5 +2147,61 @@
21472147
"expected_stdout": "",
21482148
"state": "Disabled",
21492149
"comment": "Doesn't make sense for this target"
2150+
},
2151+
{
2152+
"case": "for_loop",
2153+
"target": "ilasm-mono",
2154+
"expected_stdout": "",
2155+
"state": "Enabled",
2156+
"comment": "Failed to build on record"
2157+
},
2158+
{
2159+
"case": "for_loop",
2160+
"target": "gas-aarch64-linux",
2161+
"expected_stdout": "i: 0\ni: 1\ni: 2\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",
2162+
"state": "Enabled",
2163+
"comment": ""
2164+
},
2165+
{
2166+
"case": "for_loop",
2167+
"target": "gas-aarch64-darwin",
2168+
"expected_stdout": "i: 0\ni: 1\ni: 2\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",
2169+
"state": "Enabled",
2170+
"comment": ""
2171+
},
2172+
{
2173+
"case": "for_loop",
2174+
"target": "gas-x86_64-linux",
2175+
"expected_stdout": "i: 0\ni: 1\ni: 2\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",
2176+
"state": "Enabled",
2177+
"comment": ""
2178+
},
2179+
{
2180+
"case": "for_loop",
2181+
"target": "gas-x86_64-windows",
2182+
"expected_stdout": "i: 0\r\ni: 1\r\ni: 2\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",
2183+
"state": "Enabled",
2184+
"comment": ""
2185+
},
2186+
{
2187+
"case": "for_loop",
2188+
"target": "gas-x86_64-darwin",
2189+
"expected_stdout": "i: 0\ni: 1\ni: 2\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",
2190+
"state": "Enabled",
2191+
"comment": ""
2192+
},
2193+
{
2194+
"case": "for_loop",
2195+
"target": "6502-posix",
2196+
"expected_stdout": "i: 0\r\ni: 1\r\ni: 2\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",
2197+
"state": "Enabled",
2198+
"comment": ""
2199+
},
2200+
{
2201+
"case": "for_loop",
2202+
"target": "uxn",
2203+
"expected_stdout": "i: 0\ni: 1\ni: 2\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",
2204+
"state": "Enabled",
2205+
"comment": ""
21502206
}
21512207
]

tests/for_loop.b

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
main() {
2+
for (auto i = 0; i < 3; i++) printf("i: %lld\n", i);
3+
4+
auto j;
5+
for (j = 3; j < 9; j += 2) printf("j: %lld\n", j);
6+
7+
auto x; x = 2;
8+
for (;x < 10; x *= 2) printf("x: %lld\n", x);
9+
10+
auto y; y = 69;
11+
for (;y <= 71;) printf("y: %lld\n", y++);
12+
13+
auto z; z = 100;
14+
for (;;z++) {
15+
printf("z: %lld\n", z);
16+
if (z >= 102) goto out1;
17+
}
18+
out1:
19+
20+
for(;;) {
21+
printf("oh no!\n");
22+
goto out2;
23+
}
24+
out2:
25+
}

0 commit comments

Comments
 (0)