authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-11-24 23:44:41-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-11-24 23:44:41-07:00
log09f68c7c339075183c67c56149620c6970b6842a
tree55afa659954e143035792d44bf4edf992d26fd18
parentafac1a0123cb574e92fbc37e99e6778c51b46683

support linker directives

now you can depend on libc in zig language instead of it being hardcoded in the compiler.

7 files changed, 120 insertions(+), 7 deletions(-)

README.md+6-3
......@@ -40,12 +40,13 @@ readable, safe, optimal, and concise code to solve any computing problem.
4040
4141## Roadmap
4242
43 * don't hardcode the link against libc
4443 * C style comments.
4544 * Unit tests.
4645 * Simple .so library
4746 * Multiple files
4847 * figure out integers
48 * inline assembly and syscalls
49 * running code at compile time
4950 * implement a simple game using SDL2
5051 * How should the Widget use case be solved? In Genesis I'm using C++ and inheritance.
5152
......@@ -74,13 +75,13 @@ Root : many(TopLevelDecl) token(EOF)
7475
7576TopLevelDecl : FnDef | ExternBlock
7677
77ExternBlock : token(Extern) token(LBrace) many(FnProtoDecl) token(RBrace)
78ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnProtoDecl) token(RBrace)
7879
7980FnProto : token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type)
8081
8182FnDecl : FnProto token(Semicolon)
8283
83FnDef : FnProto Block
84FnDef : many(Directive) FnProto Block
8485
8586ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen)
8687
......@@ -101,4 +102,6 @@ ReturnStatement : token(Return) Expression token(Semicolon)
101102Expression : token(Number) | token(String) | token(Unreachable) | FnCall
102103
103104FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen)
105
106Directive : token(NumberSign) token(Symbol) token(LParen) token(String) token(RParen)
104107```
src/codegen.cpp+27-1
......@@ -56,6 +56,7 @@ struct CodeGen {
5656 HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
5757 HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table;
5858 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table;
59 HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table;
5960 TypeTableEntry *invalid_type_entry;
6061 LLVMTargetDataRef target_data_ref;
6162 unsigned pointer_size_bytes;
......@@ -86,6 +87,7 @@ CodeGen *create_codegen(AstNode *root, Buf *in_full_path) {
8687 g->fn_table.init(32);
8788 g->str_table.init(32);
8889 g->type_table.init(32);
90 g->link_table.init(32);
8991 g->is_static = false;
9092 g->build_type = CodeGenBuildTypeDebug;
9193 g->strip_debug_symbols = false;
......@@ -198,6 +200,18 @@ static void analyze_node(CodeGen *g, AstNode *node) {
198200 }
199201 break;
200202 case NodeTypeExternBlock:
203 for (int i = 0; i < node->data.extern_block.directives->length; i += 1) {
204 AstNode *directive_node = node->data.extern_block.directives->at(i);
205 Buf *name = &directive_node->data.directive.name;
206 Buf *param = &directive_node->data.directive.param;
207 if (buf_eql_str(name, "link")) {
208 g->link_table.put(param, true);
209 } else {
210 add_node_error(g, node,
211 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
212 }
213 }
214
201215 for (int fn_decl_i = 0; fn_decl_i < node->data.extern_block.fn_decls.length; fn_decl_i += 1) {
202216 AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i);
203217 analyze_node(g, fn_decl);
......@@ -306,6 +320,8 @@ static void analyze_node(CodeGen *g, AstNode *node) {
306320 analyze_node(g, child);
307321 }
308322 break;
323 case NodeTypeDirective:
324 break;
309325 }
310326}
311327
......@@ -639,6 +655,16 @@ void code_gen_link(CodeGen *g, const char *out_file) {
639655 args.append("-o");
640656 args.append(out_file);
641657 args.append((const char *)buf_ptr(&out_file_o));
642 args.append("-lc");
658
659 auto it = g->link_table.entry_iterator();
660 for (;;) {
661 auto *entry = it.next();
662 if (!entry)
663 break;
664
665 Buf *arg = buf_sprintf("-l%s", buf_ptr(entry->key));
666 args.append(buf_ptr(arg));
667 }
668
643669 os_spawn_process("ld", args, false);
644670}
src/parser.cpp+72-3
......@@ -48,6 +48,8 @@ const char *node_type_str(NodeType node_type) {
4848 return "FnCall";
4949 case NodeTypeExternBlock:
5050 return "ExternBlock";
51 case NodeTypeDirective:
52 return "Directive";
5153 }
5254 zig_unreachable();
5355}
......@@ -158,13 +160,23 @@ struct ParseContext {
158160 Buf *buf;
159161 AstNode *root;
160162 ZigList<Token> *tokens;
163 ZigList<AstNode *> *directive_list;
161164};
162165
163static AstNode *ast_create_node(NodeType type, Token *first_token) {
166static AstNode *ast_create_node_no_line_info(NodeType type) {
164167 AstNode *node = allocate<AstNode>(1);
165168 node->type = type;
169 return node;
170}
171
172static void ast_update_node_line_info(AstNode *node, Token *first_token) {
166173 node->line = first_token->start_line;
167174 node->column = first_token->start_column;
175}
176
177static AstNode *ast_create_node(NodeType type, Token *first_token) {
178 AstNode *node = ast_create_node_no_line_info(type);
179 ast_update_node_line_info(node, first_token);
168180 return node;
169181}
170182
......@@ -536,7 +548,57 @@ static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_to
536548}
537549
538550/*
539ExternBlock : token(Extern) token(LBrace) many(FnProtoDecl) token(RBrace)
551Directive : token(NumberSign) token(Symbol) token(LParen) token(String) token(RParen)
552*/
553static AstNode *ast_parse_directive(ParseContext *pc, int token_index, int *new_token_index) {
554 Token *number_sign = &pc->tokens->at(token_index);
555 token_index += 1;
556 ast_expect_token(pc, number_sign, TokenIdNumberSign);
557
558 AstNode *node = ast_create_node(NodeTypeDirective, number_sign);
559
560 Token *name_symbol = &pc->tokens->at(token_index);
561 token_index += 1;
562 ast_expect_token(pc, name_symbol, TokenIdSymbol);
563
564 ast_buf_from_token(pc, name_symbol, &node->data.directive.name);
565
566 Token *l_paren = &pc->tokens->at(token_index);
567 token_index += 1;
568 ast_expect_token(pc, l_paren, TokenIdLParen);
569
570 Token *param_str = &pc->tokens->at(token_index);
571 token_index += 1;
572 ast_expect_token(pc, param_str, TokenIdStringLiteral);
573
574 parse_string_literal(pc, param_str, &node->data.directive.param);
575
576 Token *r_paren = &pc->tokens->at(token_index);
577 token_index += 1;
578 ast_expect_token(pc, r_paren, TokenIdRParen);
579
580 *new_token_index = token_index;
581 return node;
582}
583
584static void ast_parse_directives(ParseContext *pc, int token_index, int *new_token_index,
585 ZigList<AstNode *> *directives)
586{
587 for (;;) {
588 Token *token = &pc->tokens->at(token_index);
589 if (token->id == TokenIdNumberSign) {
590 AstNode *directive_node = ast_parse_directive(pc, token_index, &token_index);
591 directives->append(directive_node);
592 } else {
593 *new_token_index = token_index;
594 return;
595 }
596 }
597 zig_unreachable();
598}
599
600/*
601ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnProtoDecl) token(RBrace)
540602*/
541603static AstNode *ast_parse_extern_block(ParseContext *pc, int token_index, int *new_token_index) {
542604 Token *extern_kw = &pc->tokens->at(token_index);
......@@ -545,6 +607,9 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int token_index, int *n
545607
546608 AstNode *node = ast_create_node(NodeTypeExternBlock, extern_kw);
547609
610 node->data.extern_block.directives = pc->directive_list;
611 pc->directive_list = nullptr;
612
548613 Token *l_brace = &pc->tokens->at(token_index);
549614 token_index += 1;
550615 ast_expect_token(pc, l_brace, TokenIdLBrace);
......@@ -570,7 +635,11 @@ static void ast_parse_top_level_decls(ParseContext *pc, int token_index, int *ne
570635{
571636 for (;;) {
572637 Token *token = &pc->tokens->at(token_index);
573 if (token->id == TokenIdKeywordFn) {
638 if (token->id == TokenIdNumberSign) {
639 assert(!pc->directive_list);
640 pc->directive_list = allocate<ZigList<AstNode*>>(1);
641 ast_parse_directives(pc, token_index, &token_index, pc->directive_list);
642 } else if (token->id == TokenIdKeywordFn) {
574643 AstNode *fn_decl_node = ast_parse_fn_def(pc, token_index, &token_index);
575644 top_level_decls->append(fn_decl_node);
576645 } else if (token->id == TokenIdKeywordExtern) {
src/parser.hpp+8
......@@ -27,6 +27,7 @@ enum NodeType {
2727 NodeTypeExpression,
2828 NodeTypeFnCall,
2929 NodeTypeExternBlock,
30 NodeTypeDirective,
3031};
3132
3233struct AstNodeRoot {
......@@ -112,9 +113,15 @@ struct AstNodeFnCall {
112113};
113114
114115struct AstNodeExternBlock {
116 ZigList<AstNode *> *directives;
115117 ZigList<AstNode *> fn_decls;
116118};
117119
120struct AstNodeDirective {
121 Buf name;
122 Buf param;
123};
124
118125struct AstNode {
119126 enum NodeType type;
120127 AstNode *parent;
......@@ -133,6 +140,7 @@ struct AstNode {
133140 AstNodeExpression expression;
134141 AstNodeFnCall fn_call;
135142 AstNodeExternBlock extern_block;
143 AstNodeDirective directive;
136144 } data;
137145};
138146
src/tokenizer.cpp+5
......@@ -218,6 +218,10 @@ ZigList<Token> *tokenize(Buf *buf) {
218218 begin_token(&t, TokenIdDash);
219219 t.state = TokenizeStateSawDash;
220220 break;
221 case '#':
222 begin_token(&t, TokenIdNumberSign);
223 end_token(&t);
224 break;
221225 default:
222226 tokenize_error(&t, "invalid character: '%c'", c);
223227 }
......@@ -321,6 +325,7 @@ static const char * token_name(Token *token) {
321325 case TokenIdColon: return "Colon";
322326 case TokenIdArrow: return "Arrow";
323327 case TokenIdDash: return "Dash";
328 case TokenIdNumberSign: return "NumberSign";
324329 }
325330 return "(invalid token)";
326331}
src/tokenizer.hpp+1
......@@ -32,6 +32,7 @@ enum TokenId {
3232 TokenIdColon,
3333 TokenIdArrow,
3434 TokenIdDash,
35 TokenIdNumberSign,
3536};
3637
3738struct Token {
test/hello.zig+1
......@@ -1,3 +1,4 @@
1#link("c")
12extern {
23 fn puts(s: *mut u8) -> i32;
34 fn exit(code: i32) -> unreachable;