After eight</a> grueling (not really) chapters of Writing a C Compiler</a>, time to implement more assembly instructions. Functions! Linkage! Commas!</p>
Lexer just has a comma now. I thought about adding the comma operator but that didn't seem worth the trouble.</p>
The AST has two new additions. Function call expressions and function declarations (which are rebranded and improved function definitions)! Other changes include how the structures themselves are defined. A program is now a list</em> of function declarations, instead of just one. How about that?</p>
These are the new AST nodes. I am not sure these compile or not yet, which I will find out when I am done with the parser. The use of It is going to be annoying fixing all the type errors throughout. Nonetheless, the parsing grammar for these new node types are going to change significantly. Here is. This is the new, tentative,
Lexer, AST, and Parser</h2>
SegmentedList</code> is discussed a couple of chapters ago as a more Arena-friendly collection type.</p>
pub const</span> Prgm</span> =</span> struct</span> {</span></span>
funcs: std.SegmentedList(FuncDecl,</span> 0</span>),</span></span>
};</span></span>
</span>
pub const</span> Block</span> =</span> struct</span> {</span></span>
body: std.SegmentedList(BlockItem,</span> 0</span>),</span></span>
};</span></span>
</span>
pub const</span> BlockItem</span> =</span> union</span>(</span>enum</span>) {</span></span>
D: Decl,</span></span>
S: Stmt,</span></span>
};</span></span>
</span>
pub const</span> Decl</span> =</span> union</span>(</span>enum</span>) {</span></span>
F: FuncDecl,</span></span>
V: VarDecl,</span></span>
};</span></span>
</span>
pub const</span> FuncDecl</span> =</span> struct</span> {</span></span>
name: []</span>const</span> u8</span>,</span></span>
params: std.SegmentedList(Identifier,</span> 0</span>),</span></span>
block:</span> ?</span>Block,</span></span>
};</span></span>
</span>
pub const</span> VarDecl</span> =</span> struct</span> {</span></span>
name: Identifier,</span></span>
init:</span> ?*</span>Expr,</span></span>
};</span></span>
</span>
pub const</span> Expr</span> =</span> union</span>(</span>enum</span>) {</span></span>
// snip --</span></span>
func_call:</span> struct</span> { Identifier, std.SegmentedList(Expr,</span> 0</span>) },</span></span>
};</span></span>
</span>
// This was implemented last chapter fixing the Segmentation Fault!</span></span>
pub const</span> Identifier</span> =</span> union</span>(</span>enum</span>) {</span></span>
name: []</span>const</span> u8</span>,</span></span>
idx: utils.StringInterner.Idx,</span></span>
};</span></span></code></pre>
parse_prgm</code>. I am not sure this is entirely correct yet.</p>
pub fn</span> parse_prgm(</span></span>
arena: std.mem.Allocator,</span></span>
tokens:</span> *</span>lexer.Tokenizer,</span></span>
) Error</span>!</span>ast.Prgm {</span></span>
var</span> funcs: std.SegmentedList(ast.FuncDecl,</span> 0</span>) </span>=</span> .{};</span></span>
</span>
while</span> (tokens.next()) </span>|</span>next_token</span>|</span> {</span></span>
tokens.put_back(next_token);</span></span>
const</span> func_decl</span> =</span> try</span> parse_func_decl(arena, tokens);</span></span>
try</span> funcs.append(arena, func_decl);</span></span>
}</span></span>
</span>
return</span> .{ .funcs</span> =</span> funcs };</span></span>
}</span></span></code></pre>
parse_func_decl</code> is the same as the old parse_func_def</code>, but with optional parameters and an optional body. Ok maybe not the same, it is a behemoth. And all this is going to get significantly more complex when adding different types than int</code>.</p>
fn</span> parse_func_decl(</span></span>
arena: std.mem.Allocator,</span></span>
tokens:</span> *</span>lexer.Tokenizer,</span></span>
) Error</span>!</span>ast.FuncDecl {</span></span>
// same old</span></span>
try</span> expect(.type_int, tokens);</span></span>
const</span> name</span> =</span> try</span> expect(.identifier, tokens);</span></span>
</span>
// new stuff !!</span></span>
var</span> params: std.SegmentedList(ast.Identifier,</span> 0</span>) </span>=</span> .{};</span></span>
{ </span>// params</span></span>
try</span> expect(.l_paren, tokens);</span></span>
const</span> next_token</span> =</span> tokens.next() </span>orelse</span></span>
return</span> error</span>.SyntaxError;</span></span>
// labelled switch to loop over multiple parameters.</span></span>
This page cannot be shown here. You can still read it on the original site — the toolbar below keeps your place in the directory.
After eight grueling (not really) chapters of Writing a C Compiler , time to implement more assembly instructions. Functions! Linkage! Commas! Lexer, AST, and Parser Lexer just has a comma now. I thought about adding the comma operator but that didn't seem worth the trouble. The AST has two new additions. Function call expressions and function declarations (which are rebranded and improved…
