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....@@ -40,12 +40,13 @@ readable, safe, optimal, and concise code to solve any computing problem.
4040
41## Roadmap41## Roadmap
4242
43 * don't hardcode the link against libc
44 * C style comments.43 * C style comments.
45 * Unit tests.44 * Unit tests.
46 * Simple .so library45 * Simple .so library
47 * Multiple files46 * Multiple files
48 * figure out integers47 * figure out integers
48 * inline assembly and syscalls
49 * running code at compile time
49 * implement a simple game using SDL250 * implement a simple game using SDL2
50 * How should the Widget use case be solved? In Genesis I'm using C++ and inheritance.51 * 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)...@@ -74,13 +75,13 @@ Root : many(TopLevelDecl) token(EOF)
7475
75TopLevelDecl : FnDef | ExternBlock76TopLevelDecl : FnDef | ExternBlock
7677
77ExternBlock : token(Extern) token(LBrace) many(FnProtoDecl) token(RBrace)78ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnProtoDecl) token(RBrace)
7879
79FnProto : token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type)80FnProto : token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type)
8081
81FnDecl : FnProto token(Semicolon)82FnDecl : FnProto token(Semicolon)
8283
83FnDef : FnProto Block84FnDef : many(Directive) FnProto Block
8485
85ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen)86ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen)
8687
...@@ -101,4 +102,6 @@ ReturnStatement : token(Return) Expression token(Semicolon)...@@ -101,4 +102,6 @@ ReturnStatement : token(Return) Expression token(Semicolon)
101Expression : token(Number) | token(String) | token(Unreachable) | FnCall102Expression : token(Number) | token(String) | token(Unreachable) | FnCall
102103
103FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen)104FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen)
105
106Directive : token(NumberSign) token(Symbol) token(LParen) token(String) token(RParen)
104```107```
src/codegen.cpp+27-1
...@@ -56,6 +56,7 @@ struct CodeGen {...@@ -56,6 +56,7 @@ struct CodeGen {
56 HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;56 HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
57 HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table;57 HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table;
58 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table;58 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table;
59 HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table;
59 TypeTableEntry *invalid_type_entry;60 TypeTableEntry *invalid_type_entry;
60 LLVMTargetDataRef target_data_ref;61 LLVMTargetDataRef target_data_ref;
61 unsigned pointer_size_bytes;62 unsigned pointer_size_bytes;
...@@ -86,6 +87,7 @@ CodeGen *create_codegen(AstNode *root, Buf *in_full_path) {...@@ -86,6 +87,7 @@ CodeGen *create_codegen(AstNode *root, Buf *in_full_path) {
86 g->fn_table.init(32);87 g->fn_table.init(32);
87 g->str_table.init(32);88 g->str_table.init(32);
88 g->type_table.init(32);89 g->type_table.init(32);
90 g->link_table.init(32);
89 g->is_static = false;91 g->is_static = false;
90 g->build_type = CodeGenBuildTypeDebug;92 g->build_type = CodeGenBuildTypeDebug;
91 g->strip_debug_symbols = false;93 g->strip_debug_symbols = false;
...@@ -198,6 +200,18 @@ static void analyze_node(CodeGen *g, AstNode *node) {...@@ -198,6 +200,18 @@ static void analyze_node(CodeGen *g, AstNode *node) {
198 }200 }
199 break;201 break;
200 case NodeTypeExternBlock:202 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
201 for (int fn_decl_i = 0; fn_decl_i < node->data.extern_block.fn_decls.length; fn_decl_i += 1) {215 for (int fn_decl_i = 0; fn_decl_i < node->data.extern_block.fn_decls.length; fn_decl_i += 1) {
202 AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i);216 AstNode *fn_decl = node->data.extern_block.fn_decls.at(fn_decl_i);
203 analyze_node(g, fn_decl);217 analyze_node(g, fn_decl);
...@@ -306,6 +320,8 @@ static void analyze_node(CodeGen *g, AstNode *node) {...@@ -306,6 +320,8 @@ static void analyze_node(CodeGen *g, AstNode *node) {
306 analyze_node(g, child);320 analyze_node(g, child);
307 }321 }
308 break;322 break;
323 case NodeTypeDirective:
324 break;
309 }325 }
310}326}
311327
...@@ -639,6 +655,16 @@ void code_gen_link(CodeGen *g, const char *out_file) {...@@ -639,6 +655,16 @@ void code_gen_link(CodeGen *g, const char *out_file) {
639 args.append("-o");655 args.append("-o");
640 args.append(out_file);656 args.append(out_file);
641 args.append((const char *)buf_ptr(&out_file_o));657 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
643 os_spawn_process("ld", args, false);669 os_spawn_process("ld", args, false);
644}670}
src/parser.cpp+72-3
...@@ -48,6 +48,8 @@ const char *node_type_str(NodeType node_type) {...@@ -48,6 +48,8 @@ const char *node_type_str(NodeType node_type) {
48 return "FnCall";48 return "FnCall";
49 case NodeTypeExternBlock:49 case NodeTypeExternBlock:
50 return "ExternBlock";50 return "ExternBlock";
51 case NodeTypeDirective:
52 return "Directive";
51 }53 }
52 zig_unreachable();54 zig_unreachable();
53}55}
...@@ -158,13 +160,23 @@ struct ParseContext {...@@ -158,13 +160,23 @@ struct ParseContext {
158 Buf *buf;160 Buf *buf;
159 AstNode *root;161 AstNode *root;
160 ZigList<Token> *tokens;162 ZigList<Token> *tokens;
163 ZigList<AstNode *> *directive_list;
161};164};
162165
163static AstNode *ast_create_node(NodeType type, Token *first_token) {166static AstNode *ast_create_node_no_line_info(NodeType type) {
164 AstNode *node = allocate<AstNode>(1);167 AstNode *node = allocate<AstNode>(1);
165 node->type = type;168 node->type = type;
169 return node;
170}
171
172static void ast_update_node_line_info(AstNode *node, Token *first_token) {
166 node->line = first_token->start_line;173 node->line = first_token->start_line;
167 node->column = first_token->start_column;174 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);
168 return node;180 return node;
169}181}
170182
...@@ -536,7 +548,57 @@ static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_to...@@ -536,7 +548,57 @@ static AstNode *ast_parse_fn_decl(ParseContext *pc, int token_index, int *new_to
536}548}
537549
538/*550/*
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)
540*/602*/
541static AstNode *ast_parse_extern_block(ParseContext *pc, int token_index, int *new_token_index) {603static AstNode *ast_parse_extern_block(ParseContext *pc, int token_index, int *new_token_index) {
542 Token *extern_kw = &pc->tokens->at(token_index);604 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...@@ -545,6 +607,9 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int token_index, int *n
545607
546 AstNode *node = ast_create_node(NodeTypeExternBlock, extern_kw);608 AstNode *node = ast_create_node(NodeTypeExternBlock, extern_kw);
547609
610 node->data.extern_block.directives = pc->directive_list;
611 pc->directive_list = nullptr;
612
548 Token *l_brace = &pc->tokens->at(token_index);613 Token *l_brace = &pc->tokens->at(token_index);
549 token_index += 1;614 token_index += 1;
550 ast_expect_token(pc, l_brace, TokenIdLBrace);615 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...@@ -570,7 +635,11 @@ static void ast_parse_top_level_decls(ParseContext *pc, int token_index, int *ne
570{635{
571 for (;;) {636 for (;;) {
572 Token *token = &pc->tokens->at(token_index);637 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) {
574 AstNode *fn_decl_node = ast_parse_fn_def(pc, token_index, &token_index);643 AstNode *fn_decl_node = ast_parse_fn_def(pc, token_index, &token_index);
575 top_level_decls->append(fn_decl_node);644 top_level_decls->append(fn_decl_node);
576 } else if (token->id == TokenIdKeywordExtern) {645 } else if (token->id == TokenIdKeywordExtern) {
src/parser.hpp+8
...@@ -27,6 +27,7 @@ enum NodeType {...@@ -27,6 +27,7 @@ enum NodeType {
27 NodeTypeExpression,27 NodeTypeExpression,
28 NodeTypeFnCall,28 NodeTypeFnCall,
29 NodeTypeExternBlock,29 NodeTypeExternBlock,
30 NodeTypeDirective,
30};31};
3132
32struct AstNodeRoot {33struct AstNodeRoot {
...@@ -112,9 +113,15 @@ struct AstNodeFnCall {...@@ -112,9 +113,15 @@ struct AstNodeFnCall {
112};113};
113114
114struct AstNodeExternBlock {115struct AstNodeExternBlock {
116 ZigList<AstNode *> *directives;
115 ZigList<AstNode *> fn_decls;117 ZigList<AstNode *> fn_decls;
116};118};
117119
120struct AstNodeDirective {
121 Buf name;
122 Buf param;
123};
124
118struct AstNode {125struct AstNode {
119 enum NodeType type;126 enum NodeType type;
120 AstNode *parent;127 AstNode *parent;
...@@ -133,6 +140,7 @@ struct AstNode {...@@ -133,6 +140,7 @@ struct AstNode {
133 AstNodeExpression expression;140 AstNodeExpression expression;
134 AstNodeFnCall fn_call;141 AstNodeFnCall fn_call;
135 AstNodeExternBlock extern_block;142 AstNodeExternBlock extern_block;
143 AstNodeDirective directive;
136 } data;144 } data;
137};145};
138146
src/tokenizer.cpp+5
...@@ -218,6 +218,10 @@ ZigList<Token> *tokenize(Buf *buf) {...@@ -218,6 +218,10 @@ ZigList<Token> *tokenize(Buf *buf) {
218 begin_token(&t, TokenIdDash);218 begin_token(&t, TokenIdDash);
219 t.state = TokenizeStateSawDash;219 t.state = TokenizeStateSawDash;
220 break;220 break;
221 case '#':
222 begin_token(&t, TokenIdNumberSign);
223 end_token(&t);
224 break;
221 default:225 default:
222 tokenize_error(&t, "invalid character: '%c'", c);226 tokenize_error(&t, "invalid character: '%c'", c);
223 }227 }
...@@ -321,6 +325,7 @@ static const char * token_name(Token *token) {...@@ -321,6 +325,7 @@ static const char * token_name(Token *token) {
321 case TokenIdColon: return "Colon";325 case TokenIdColon: return "Colon";
322 case TokenIdArrow: return "Arrow";326 case TokenIdArrow: return "Arrow";
323 case TokenIdDash: return "Dash";327 case TokenIdDash: return "Dash";
328 case TokenIdNumberSign: return "NumberSign";
324 }329 }
325 return "(invalid token)";330 return "(invalid token)";
326}331}
src/tokenizer.hpp+1
...@@ -32,6 +32,7 @@ enum TokenId {...@@ -32,6 +32,7 @@ enum TokenId {
32 TokenIdColon,32 TokenIdColon,
33 TokenIdArrow,33 TokenIdArrow,
34 TokenIdDash,34 TokenIdDash,
35 TokenIdNumberSign,
35};36};
3637
37struct Token {38struct Token {
test/hello.zig+1
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1#link("c")
1extern {2extern {
2 fn puts(s: *mut u8) -> i32;3 fn puts(s: *mut u8) -> i32;
3 fn exit(code: i32) -> unreachable;4 fn exit(code: i32) -> unreachable;