authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-10 15:34:38-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-10 15:34:38-07:00
log0dbee2300ed28c18ecccaf71f10f68eb2da71266
treeac804032eccb2f07258b45023739b694ee937d8c
parent3e8a98fa619516d0617a827a79601264a554d88b

add inline assembly support


15 files changed, 383 insertions(+), 20 deletions(-)

CMakeLists.txt+6
......@@ -115,7 +115,12 @@ set(C_HEADERS
115115 "${CMAKE_SOURCE_DIR}/c_headers/xtestintrin.h"
116116)
117117
118set(ZIG_STD_SRC
119 "${CMAKE_SOURCE_DIR}/std/bootstrap.zig"
120)
121
118122set(C_HEADERS_DEST "lib/zig/include")
123set(ZIG_STD_DEST "lib/zig/std")
119124set(CONFIGURE_OUT_FILE "${CMAKE_BINARY_DIR}/config.h")
120125configure_file (
121126 "${CMAKE_SOURCE_DIR}/src/config.h.in"
......@@ -142,6 +147,7 @@ target_link_libraries(zig LINK_PUBLIC
142147install(TARGETS zig DESTINATION bin)
143148
144149install(FILES ${C_HEADERS} DESTINATION ${C_HEADERS_DEST})
150install(FILES ${ZIG_STD_SRC} DESTINATION ${ZIG_STD_DEST})
145151
146152add_executable(run_tests ${TEST_SOURCES})
147153target_link_libraries(run_tests)
README.md+14-2
......@@ -58,7 +58,6 @@ compromises backward compatibility.
5858 * structs
5959 * loops
6060 * enums
61 * inline assembly and syscalls
6261 * conditional compilation and ability to check target platform and architecture
6362 * main function with command line arguments
6463 * void pointer constant
......@@ -83,10 +82,23 @@ compromises backward compatibility.
8382
8483## Building
8584
85### Debug / Development Build
86
8687```
8788mkdir build
8889cd build
89cmake ..
90cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd)
9091make
92make install
9193./run_tests
9294```
95
96### Release / Install Build
97
98```
99mkdir build
100cd build
101cmake .. -DCMAKE_BUILD_TYPE=Release
102make
103sudo make install
104```
doc/langref.md+9-1
......@@ -70,7 +70,15 @@ VariableDeclaration : token(Let) option(token(Mut)) token(Symbol) (token(Eq) Exp
7070
7171Expression : BlockExpression | NonBlockExpression
7272
73NonBlockExpression : ReturnExpression | AssignmentExpression
73NonBlockExpression : ReturnExpression | AssignmentExpression | AsmExpression
74
75AsmExpression : token(Asm) option(token(Volatile)) token(LParen) token(String) option(AsmOutput) token(RParen)
76
77AsmOutput : token(Colon) list(AsmOutputItem, token(Comma)) option(AsmInput)
78
79AsmInput : token(Colon) list(AsmInputItem, token(Comma)) option(AsmClobbers)
80
81AsmClobbers: token(Colon) list(token(String), token(Comma))
7482
7583AssignmentExpression : BoolOrExpression token(Equal) BoolOrExpression | BoolOrExpression
7684
doc/vim/syntax/zig.vim+2-2
......@@ -7,8 +7,8 @@ if exists("b:current_syntax")
77 finish
88endif
99
10syn keyword zigKeyword fn return mut const extern unreachable export pub as use while
11syn keyword zigKeyword if else let void goto type enum struct continue break match
10syn keyword zigKeyword fn return mut const extern unreachable export pub as use while asm
11syn keyword zigKeyword if else let void goto type enum struct continue break match volatile
1212syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128
1313
1414syn keyword zigConstant null
example/hello_world/hello2.zig created+11
......@@ -0,0 +1,11 @@
1export executable "hello";
2
3#link("c")
4extern {
5 fn printf(__format: *const u8, ...) -> i32;
6}
7
8export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
9 printf("argc = %zu\n", argc);
10 return 0;
11}
src/analyze.cpp+29-2
......@@ -43,6 +43,7 @@ static AstNode *first_executing_node(AstNode *node) {
4343 case NodeTypeIfExpr:
4444 case NodeTypeLabel:
4545 case NodeTypeGoto:
46 case NodeTypeAsmExpr:
4647 return node;
4748 }
4849 zig_panic("unreachable");
......@@ -205,8 +206,26 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
205206 for (int i = 0; i < node->data.fn_proto.directives->length; i += 1) {
206207 AstNode *directive_node = node->data.fn_proto.directives->at(i);
207208 Buf *name = &directive_node->data.directive.name;
208 add_node_error(g, directive_node,
209 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
209
210 if (buf_eql_str(name, "attribute")) {
211 Buf *attr_name = &directive_node->data.directive.param;
212 if (fn_table_entry->fn_def_node) {
213 if (buf_eql_str(attr_name, "naked")) {
214 fn_table_entry->fn_attr_list.append(FnAttrIdNaked);
215 } else if (buf_eql_str(attr_name, "alwaysinline")) {
216 fn_table_entry->fn_attr_list.append(FnAttrIdAlwaysInline);
217 } else {
218 add_node_error(g, directive_node,
219 buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
220 }
221 } else {
222 add_node_error(g, directive_node,
223 buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
224 }
225 } else {
226 add_node_error(g, directive_node,
227 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
228 }
210229 }
211230
212231 for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
......@@ -338,6 +357,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
338357
339358 resolve_function_proto(g, proto_node, fn_table_entry);
340359
360
341361 assert(!proto_node->codegen_node);
342362 proto_node->codegen_node = allocate<CodeGenNode>(1);
343363 proto_node->codegen_node->data.fn_proto_node.fn_table_entry = fn_table_entry;
......@@ -415,6 +435,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
415435 case NodeTypeIfExpr:
416436 case NodeTypeLabel:
417437 case NodeTypeGoto:
438 case NodeTypeAsmExpr:
418439 zig_unreachable();
419440 }
420441}
......@@ -626,6 +647,11 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
626647 return_type = g->builtin_types.entry_unreachable;
627648 break;
628649 }
650 case NodeTypeAsmExpr:
651 {
652 return_type = g->builtin_types.entry_void;
653 break;
654 }
629655 case NodeTypeBinOpExpr:
630656 {
631657 switch (node->data.bin_op_expr.bin_op) {
......@@ -1004,6 +1030,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
10041030 case NodeTypeIfExpr:
10051031 case NodeTypeLabel:
10061032 case NodeTypeGoto:
1033 case NodeTypeAsmExpr:
10071034 zig_unreachable();
10081035 }
10091036}
src/analyze.hpp+8
......@@ -82,6 +82,11 @@ struct LabelTableEntry {
8282 bool entered_from_fallthrough;
8383};
8484
85enum FnAttrId {
86 FnAttrIdNaked,
87 FnAttrIdAlwaysInline,
88};
89
8590struct FnTableEntry {
8691 LLVMValueRef fn_value;
8792 AstNode *proto_node;
......@@ -90,6 +95,7 @@ struct FnTableEntry {
9095 bool internal_linkage;
9196 unsigned calling_convention;
9297 ImportTableEntry *import_entry;
98 ZigList<FnAttrId> fn_attr_list;
9399
94100 // reminder: hash tables must be initialized before use
95101 HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
......@@ -113,6 +119,7 @@ struct CodeGen {
113119 TypeTableEntry *entry_bool;
114120 TypeTableEntry *entry_u8;
115121 TypeTableEntry *entry_i32;
122 TypeTableEntry *entry_isize;
116123 TypeTableEntry *entry_f32;
117124 TypeTableEntry *entry_string_literal;
118125 TypeTableEntry *entry_void;
......@@ -124,6 +131,7 @@ struct CodeGen {
124131 unsigned pointer_size_bytes;
125132 bool is_static;
126133 bool strip_debug_symbols;
134 bool insert_bootstrap_code;
127135 CodeGenBuildType build_type;
128136 LLVMTargetMachineRef target_machine;
129137 bool is_native_target;
src/codegen.cpp+101-12
......@@ -609,6 +609,41 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i
609609 return return_value;
610610}
611611
612static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
613 assert(node->type == NodeTypeAsmExpr);
614
615 Buf *src_template = &node->data.asm_expr.asm_template;
616
617 Buf llvm_template = BUF_INIT;
618 buf_resize(&llvm_template, 0);
619
620 for (int token_i = 0; token_i < node->data.asm_expr.token_list.length; token_i += 1) {
621 AsmToken *asm_token = &node->data.asm_expr.token_list.at(token_i);
622 switch (asm_token->id) {
623 case AsmTokenIdTemplate:
624 for (int offset = asm_token->start; offset < asm_token->end; offset += 1) {
625 uint8_t c = *((uint8_t*)(buf_ptr(src_template) + offset));
626 if (c == '$') {
627 buf_append_str(&llvm_template, "$$");
628 } else {
629 buf_append_char(&llvm_template, c);
630 }
631 }
632 break;
633 case AsmTokenIdPercent:
634 buf_append_char(&llvm_template, '%');
635 break;
636 }
637 }
638
639 LLVMTypeRef function_type = LLVMFunctionType(LLVMVoidType(), nullptr, 0, false);
640
641 LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template), "", true, false);
642
643 add_debug_source_node(g, node);
644 return LLVMBuildCall(g->builder, asm_fn, nullptr, 0, "");
645}
646
612647static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
613648 switch (node->type) {
614649 case NodeTypeBinOpExpr:
......@@ -663,6 +698,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
663698 return LLVMConstNull(LLVMInt1Type());
664699 case NodeTypeIfExpr:
665700 return gen_if_expr(g, node);
701 case NodeTypeAsmExpr:
702 return gen_asm_expr(g, node);
666703 case NodeTypeNumberLiteral:
667704 {
668705 Buf *number_str = &node->data.number;
......@@ -762,6 +799,16 @@ static LLVMZigDISubroutineType *create_di_function_type(CodeGen *g, AstNodeFnPro
762799 return LLVMZigCreateSubroutineType(g->dbuilder, di_file, types, types_len, 0);
763800}
764801
802static LLVMAttribute to_llvm_fn_attr(FnAttrId attr_id) {
803 switch (attr_id) {
804 case FnAttrIdNaked:
805 return LLVMNakedAttribute;
806 case FnAttrIdAlwaysInline:
807 return LLVMAlwaysInlineAttribute;
808 }
809 zig_unreachable();
810}
811
765812static void do_code_gen(CodeGen *g) {
766813 assert(!g->errors.length);
767814
......@@ -789,6 +836,11 @@ static void do_code_gen(CodeGen *g) {
789836 LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, param_count, fn_proto->is_var_args);
790837 LLVMValueRef fn = LLVMAddFunction(g->module, buf_ptr(&fn_proto->name), function_type);
791838
839 for (int attr_i = 0; attr_i < fn_table_entry->fn_attr_list.length; attr_i += 1) {
840 FnAttrId attr_id = fn_table_entry->fn_attr_list.at(attr_i);
841 LLVMAddFunctionAttr(fn, to_llvm_fn_attr(attr_id));
842 }
843
792844 LLVMSetLinkage(fn, fn_table_entry->internal_linkage ? LLVMInternalLinkage : LLVMExternalLinkage);
793845
794846 if (type_is_unreachable(g, fn_proto->return_type)) {
......@@ -966,6 +1018,19 @@ static void define_primitive_types(CodeGen *g) {
9661018 g->type_table.put(&entry->name, entry);
9671019 g->builtin_types.entry_i32 = entry;
9681020 }
1021 {
1022 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
1023 entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8);
1024 buf_init_from_str(&entry->name, "isize");
1025 entry->size_in_bits = g->pointer_size_bytes * 8;
1026 entry->align_in_bits = g->pointer_size_bytes * 8;
1027 entry->data.integral.is_signed = true;
1028 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
1029 entry->size_in_bits, entry->align_in_bits,
1030 LLVMZigEncoding_DW_ATE_signed());
1031 g->type_table.put(&entry->name, entry);
1032 g->builtin_types.entry_isize = entry;
1033 }
9691034 {
9701035 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
9711036 entry->type_ref = LLVMFloatType();
......@@ -1121,20 +1186,30 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *source_path, Buf *sou
11211186 assert(import_entry->root->type == NodeTypeRoot);
11221187 for (int decl_i = 0; decl_i < import_entry->root->data.root.top_level_decls.length; decl_i += 1) {
11231188 AstNode *top_level_decl = import_entry->root->data.root.top_level_decls.at(decl_i);
1124 if (top_level_decl->type != NodeTypeUse)
1125 continue;
11261189
1127 auto entry = g->import_table.maybe_get(&top_level_decl->data.use.path);
1128 if (!entry) {
1129 Buf full_path = BUF_INIT;
1130 os_path_join(g->root_source_dir, &top_level_decl->data.use.path, &full_path);
1131 Buf *import_code = buf_alloc();
1132 if ((err = os_fetch_file_path(&full_path, import_code))) {
1133 add_node_error(g, top_level_decl,
1134 buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err)));
1135 break;
1190 if (top_level_decl->type == NodeTypeUse) {
1191 auto entry = g->import_table.maybe_get(&top_level_decl->data.use.path);
1192 if (!entry) {
1193 Buf full_path = BUF_INIT;
1194 os_path_join(g->root_source_dir, &top_level_decl->data.use.path, &full_path);
1195 Buf *import_code = buf_alloc();
1196 if ((err = os_fetch_file_path(&full_path, import_code))) {
1197 add_node_error(g, top_level_decl,
1198 buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err)));
1199 break;
1200 }
1201 codegen_add_code(g, &top_level_decl->data.use.path, import_code);
1202 }
1203 } else if (top_level_decl->type == NodeTypeFnDef) {
1204 AstNode *proto_node = top_level_decl->data.fn_def.fn_proto;
1205 assert(proto_node->type == NodeTypeFnProto);
1206 Buf *proto_name = &proto_node->data.fn_proto.name;
1207
1208 bool is_exported = (proto_node->data.fn_proto.visib_mod == FnProtoVisibModExport);
1209
1210 if (buf_eql_str(proto_name, "main") && is_exported) {
1211 g->insert_bootstrap_code = true;
11361212 }
1137 codegen_add_code(g, &top_level_decl->data.use.path, import_code);
11381213 }
11391214 }
11401215
......@@ -1146,6 +1221,17 @@ void codegen_add_root_code(CodeGen *g, Buf *source_path, Buf *source_code) {
11461221
11471222 g->root_import = codegen_add_code(g, source_path, source_code);
11481223
1224 if (g->insert_bootstrap_code) {
1225 Buf *path_to_bootstrap_src = buf_sprintf("%s/bootstrap.zig", ZIG_STD_DIR);
1226 Buf *import_code = buf_alloc();
1227 int err;
1228 if ((err = os_fetch_file_path(path_to_bootstrap_src, import_code))) {
1229 zig_panic("unable to open '%s': %s", buf_ptr(path_to_bootstrap_src), err_str(err));
1230 }
1231
1232 codegen_add_code(g, path_to_bootstrap_src, import_code);
1233 }
1234
11491235 if (g->verbose) {
11501236 fprintf(stderr, "\nSemantic Analysis:\n");
11511237 fprintf(stderr, "--------------------\n");
......@@ -1185,6 +1271,9 @@ static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) {
11851271 } else if (type_entry == g->builtin_types.entry_i32) {
11861272 g->c_stdint_used = true;
11871273 buf_init_from_str(out_buf, "int32_t");
1274 } else if (type_entry == g->builtin_types.entry_isize) {
1275 g->c_stdint_used = true;
1276 buf_init_from_str(out_buf, "intptr_t");
11881277 } else if (type_entry == g->builtin_types.entry_f32) {
11891278 buf_init_from_str(out_buf, "float");
11901279 } else if (type_entry == g->builtin_types.entry_unreachable) {
src/config.h.in+1
......@@ -7,5 +7,6 @@
77#define ZIG_VERSION_STRING "@ZIG_VERSION@"
88
99#define ZIG_HEADERS_DIR "@CMAKE_INSTALL_PREFIX@/@C_HEADERS_DEST@"
10#define ZIG_STD_DIR "@CMAKE_INSTALL_PREFIX@/@ZIG_STD_DEST@"
1011
1112#endif
src/parser.cpp+118-1
......@@ -104,6 +104,8 @@ const char *node_type_str(NodeType node_type) {
104104 return "Label";
105105 case NodeTypeGoto:
106106 return "Label";
107 case NodeTypeAsmExpr:
108 return "AsmExpr";
107109 }
108110 zig_unreachable();
109111}
......@@ -290,6 +292,9 @@ void ast_print(AstNode *node, int indent) {
290292 case NodeTypeGoto:
291293 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.go_to.name));
292294 break;
295 case NodeTypeAsmExpr:
296 fprintf(stderr, "%s\n", node_type_str(node->type));
297 break;
293298 }
294299}
295300
......@@ -360,6 +365,71 @@ static void ast_buf_from_token(ParseContext *pc, Token *token, Buf *buf) {
360365 buf_init_from_mem(buf, buf_ptr(pc->buf) + token->start_pos, token->end_pos - token->start_pos);
361366}
362367
368static void parse_asm_template(ParseContext *pc, AstNode *node) {
369 Buf *asm_template = &node->data.asm_expr.asm_template;
370
371 enum State {
372 StateStart,
373 StatePercent,
374 StateTemplate,
375 };
376
377 ZigList<AsmToken> *tok_list = &node->data.asm_expr.token_list;
378 assert(tok_list->length == 0);
379
380 AsmToken *cur_tok = nullptr;
381
382 enum State state = StateStart;
383
384 for (int i = 0; i < buf_len(asm_template); i += 1) {
385 uint8_t c = *((uint8_t*)buf_ptr(asm_template) + i);
386 switch (state) {
387 case StateStart:
388 if (c == '%') {
389 tok_list->add_one();
390 cur_tok = &tok_list->last();
391 cur_tok->id = AsmTokenIdPercent;
392 cur_tok->start = i;
393 state = StatePercent;
394 } else {
395 tok_list->add_one();
396 cur_tok = &tok_list->last();
397 cur_tok->id = AsmTokenIdTemplate;
398 cur_tok->start = i;
399 state = StateTemplate;
400 }
401 break;
402 case StatePercent:
403 if (c == '%') {
404 cur_tok->end = i;
405 state = StateStart;
406 } else {
407 zig_panic("TODO handle assembly tokenize error");
408 }
409 break;
410 case StateTemplate:
411 if (c == '%') {
412 cur_tok->end = i;
413 i -= 1;
414 cur_tok = nullptr;
415 state = StateStart;
416 }
417 break;
418 }
419 }
420
421 switch (state) {
422 case StateStart:
423 break;
424 case StatePercent:
425 zig_panic("TODO handle assembly tokenize error eof");
426 break;
427 case StateTemplate:
428 cur_tok->end = buf_len(asm_template);
429 break;
430 }
431}
432
363433static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf) {
364434 // skip the double quotes at beginning and end
365435 // convert escape sequences
......@@ -1264,7 +1334,50 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mand
12641334}
12651335
12661336/*
1267NonBlockExpression : ReturnExpression | AssignmentExpression
1337AsmExpression : token(Asm) option(token(Volatile)) token(LParen) token(String) option(AsmOutput) token(RParen)
1338*/
1339static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mandatory) {
1340 Token *asm_token = &pc->tokens->at(*token_index);
1341
1342 if (asm_token->id != TokenIdKeywordAsm) {
1343 if (mandatory) {
1344 ast_invalid_token_error(pc, asm_token);
1345 } else {
1346 return nullptr;
1347 }
1348 }
1349
1350 AstNode *node = ast_create_node(pc, NodeTypeAsmExpr, asm_token);
1351
1352 *token_index += 1;
1353 Token *lparen_tok = &pc->tokens->at(*token_index);
1354
1355 if (lparen_tok->id == TokenIdKeywordVolatile) {
1356 node->data.asm_expr.is_volatile = true;
1357
1358 *token_index += 1;
1359 lparen_tok = &pc->tokens->at(*token_index);
1360 }
1361
1362 ast_expect_token(pc, lparen_tok, TokenIdLParen);
1363 *token_index += 1;
1364
1365 Token *template_tok = &pc->tokens->at(*token_index);
1366 ast_expect_token(pc, template_tok, TokenIdStringLiteral);
1367 *token_index += 1;
1368
1369 parse_string_literal(pc, template_tok, &node->data.asm_expr.asm_template);
1370 parse_asm_template(pc, node);
1371
1372 Token *rparen_tok = &pc->tokens->at(*token_index);
1373 ast_expect_token(pc, rparen_tok, TokenIdRParen);
1374 *token_index += 1;
1375
1376 return node;
1377}
1378
1379/*
1380NonBlockExpression : ReturnExpression | AssignmentExpression | AsmExpression
12681381*/
12691382static AstNode *ast_parse_non_block_expr(ParseContext *pc, int *token_index, bool mandatory) {
12701383 Token *token = &pc->tokens->at(*token_index);
......@@ -1277,6 +1390,10 @@ static AstNode *ast_parse_non_block_expr(ParseContext *pc, int *token_index, boo
12771390 if (ass_expr)
12781391 return ass_expr;
12791392
1393 AstNode *asm_expr = ast_parse_asm_expr(pc, token_index, false);
1394 if (asm_expr)
1395 return asm_expr;
1396
12801397 if (mandatory)
12811398 ast_invalid_token_error(pc, token);
12821399
src/parser.hpp+20
......@@ -16,6 +16,7 @@
1616struct AstNode;
1717struct CodeGenNode;
1818struct ImportTableEntry;
19struct AsmToken;
1920
2021enum NodeType {
2122 NodeTypeRoot,
......@@ -45,6 +46,7 @@ enum NodeType {
4546 NodeTypeIfExpr,
4647 NodeTypeLabel,
4748 NodeTypeGoto,
49 NodeTypeAsmExpr,
4850};
4951
5052struct AstNodeRoot {
......@@ -203,6 +205,12 @@ struct AstNodeGoto {
203205 Buf name;
204206};
205207
208struct AstNodeAsmExpr {
209 bool is_volatile;
210 Buf asm_template;
211 ZigList<AsmToken> token_list;
212};
213
206214struct AstNode {
207215 enum NodeType type;
208216 int line;
......@@ -231,6 +239,7 @@ struct AstNode {
231239 AstNodeIfExpr if_expr;
232240 AstNodeLabel label;
233241 AstNodeGoto go_to;
242 AstNodeAsmExpr asm_expr;
234243 Buf number;
235244 Buf string;
236245 Buf symbol;
......@@ -238,6 +247,17 @@ struct AstNode {
238247 } data;
239248};
240249
250enum AsmTokenId {
251 AsmTokenIdTemplate,
252 AsmTokenIdPercent,
253};
254
255struct AsmToken {
256 enum AsmTokenId id;
257 int start;
258 int end;
259};
260
241261__attribute__ ((format (printf, 2, 3)))
242262void ast_token_error(Token *token, const char *format, ...);
243263
src/tokenizer.cpp+43
......@@ -197,6 +197,10 @@ static void end_token(Tokenize *t) {
197197 t->cur_tok->id = TokenIdKeywordElse;
198198 } else if (mem_eql_str(token_mem, token_len, "goto")) {
199199 t->cur_tok->id = TokenIdKeywordGoto;
200 } else if (mem_eql_str(token_mem, token_len, "volatile")) {
201 t->cur_tok->id = TokenIdKeywordVolatile;
202 } else if (mem_eql_str(token_mem, token_len, "asm")) {
203 t->cur_tok->id = TokenIdKeywordAsm;
200204 }
201205
202206 t->cur_tok = nullptr;
......@@ -637,6 +641,8 @@ static const char * token_name(Token *token) {
637641 case TokenIdKeywordIf: return "If";
638642 case TokenIdKeywordElse: return "Else";
639643 case TokenIdKeywordGoto: return "Goto";
644 case TokenIdKeywordVolatile: return "Volatile";
645 case TokenIdKeywordAsm: return "Asm";
640646 case TokenIdLParen: return "LParen";
641647 case TokenIdRParen: return "RParen";
642648 case TokenIdComma: return "Comma";
......@@ -687,3 +693,40 @@ void print_tokens(Buf *buf, ZigList<Token> *tokens) {
687693 fprintf(stderr, "\n");
688694 }
689695}
696
697bool is_printable(uint8_t c) {
698 switch (c) {
699 default:
700 return false;
701 case DIGIT:
702 case ALPHA:
703 case '!':
704 case '#':
705 case '$':
706 case '%':
707 case '&':
708 case '\'':
709 case '(':
710 case ')':
711 case '*':
712 case '+':
713 case ',':
714 case '-':
715 case '.':
716 case '/':
717 case ':':
718 case ';':
719 case '<':
720 case '=':
721 case '>':
722 case '?':
723 case '@':
724 case '^':
725 case '_':
726 case '`':
727 case '~':
728 case ' ':
729 return true;
730 }
731}
732
src/tokenizer.hpp+4
......@@ -30,6 +30,8 @@ enum TokenId {
3030 TokenIdKeywordIf,
3131 TokenIdKeywordElse,
3232 TokenIdKeywordGoto,
33 TokenIdKeywordAsm,
34 TokenIdKeywordVolatile,
3335 TokenIdLParen,
3436 TokenIdRParen,
3537 TokenIdComma,
......@@ -90,4 +92,6 @@ void tokenize(Buf *buf, Tokenization *out_tokenization);
9092
9193void print_tokens(Buf *buf, ZigList<Token> *tokens);
9294
95bool is_printable(uint8_t c);
96
9397#endif
std/bootstrap.zig created+16
......@@ -0,0 +1,16 @@
1
2// TODO conditionally compile this differently for non-ELF
3#attribute("naked")
4export fn _start() -> unreachable {
5 // TODO conditionally compile this differently for other architectures and other OSes
6 asm volatile ("
7 mov (%%rsp), %%rdi // first parameter is argc
8 lea 0x8(%%rsp), %%rsi // second parameter is argv
9 lea 0x10(%%rsp,%%rdi,8), %%rdx // third paremeter is env
10 callq main
11 mov %%rax, %%rdi // return value is the parameter to exit syscall
12 mov $60, %%rax // 60 is exit syscall number
13 syscall
14 ");
15 unreachable
16}
test/run_tests.cpp+1
......@@ -397,6 +397,7 @@ loop_2_end:
397397 exit(0);
398398}
399399 )SOURCE", "OK\n");
400
400401}
401402
402403static void add_compile_failure_test_cases(void) {