authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-11 03:55:26-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-11 03:55:26-07:00
logd697404f640d25be5fc1a02c5144362c2b329902
tree73e26c0efea7b15335fe973142e6f91df63fdda8
parent15ba5bc54e286fb64d67e38857ede4b0dac9c841

hello world working without libc


8 files changed, 442 insertions(+), 67 deletions(-)

doc/langref.md+4
......@@ -78,6 +78,10 @@ AsmOutput : token(Colon) list(AsmOutputItem, token(Comma)) option(AsmInput)
7878
7979AsmInput : token(Colon) list(AsmInputItem, token(Comma)) option(AsmClobbers)
8080
81AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) token(Symbol) token(RParen)
82
83AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen)
84
8185AsmClobbers: token(Colon) list(token(String), token(Comma))
8286
8387AssignmentExpression : BoolOrExpression token(Equal) BoolOrExpression | BoolOrExpression
example/hello_world/hello2.zig+1-1
......@@ -3,6 +3,6 @@ export executable "hello";
33use "std.zig";
44
55export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
6 print_str("Hello, world!", 13);
6 print_str("Hello, world!", 13 as isize);
77 return 0;
88}
src/analyze.cpp+49-12
......@@ -536,6 +536,20 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i
536536 return return_type;
537537}
538538
539static TypeTableEntry *analyze_variable_name(CodeGen *g, BlockContext *context,
540 AstNode *node, Buf *variable_name)
541{
542 LocalVariableTableEntry *local_variable = find_local_variable(context, variable_name);
543 if (local_variable) {
544 return local_variable->type;
545 } else {
546 // TODO: check global variables also
547 add_node_error(g, node,
548 buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
549 return g->builtin_types.entry_invalid;
550 }
551}
552
539553static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
540554 TypeTableEntry *expected_type, AstNode *node)
541555{
......@@ -649,6 +663,15 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
649663 }
650664 case NodeTypeAsmExpr:
651665 {
666 for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) {
667 AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
668 analyze_variable_name(g, context, node, &asm_output->variable_name);
669 }
670 for (int i = 0; i < node->data.asm_expr.input_list.length; i += 1) {
671 AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
672 analyze_expression(g, import, context, nullptr, asm_input->expr);
673 }
674
652675 return_type = g->builtin_types.entry_void;
653676 break;
654677 }
......@@ -835,22 +858,36 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
835858
836859 case NodeTypeSymbol:
837860 {
838 Buf *symbol_name = &node->data.symbol;
839 LocalVariableTableEntry *local_variable = find_local_variable(context, symbol_name);
840 if (local_variable) {
841 return_type = local_variable->type;
842 } else {
843 // TODO: check global variables also
844 add_node_error(g, node,
845 buf_sprintf("use of undeclared identifier '%s'", buf_ptr(symbol_name)));
846 return_type = g->builtin_types.entry_invalid;
847 }
861 return_type = analyze_variable_name(g, context, node, &node->data.symbol);
848862 break;
849863 }
850864 case NodeTypeCastExpr:
851 zig_panic("TODO analyze_expression cast expr");
852 break;
865 {
866 TypeTableEntry *wanted_type = resolve_type(g, node->data.cast_expr.type);
867 TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr,
868 node->data.cast_expr.expr);
869
870 if (wanted_type->id == TypeTableEntryIdInvalid ||
871 actual_type->id == TypeTableEntryIdInvalid)
872 {
873 return_type = g->builtin_types.entry_invalid;
874 break;
875 }
853876
877 // special casing this for now, TODO think about casting and do a general solution
878 if (wanted_type == g->builtin_types.entry_isize &&
879 actual_type->id == TypeTableEntryIdPointer)
880 {
881 return_type = wanted_type;
882 } else if (wanted_type == g->builtin_types.entry_isize &&
883 actual_type->id == TypeTableEntryIdInt)
884 {
885 return_type = wanted_type;
886 } else {
887 zig_panic("TODO analyze_expression cast expr");
888 }
889 break;
890 }
854891 case NodeTypePrefixOpExpr:
855892 switch (node->data.prefix_op_expr.prefix_op) {
856893 case PrefixOpBoolNot:
src/codegen.cpp+108-10
......@@ -232,12 +232,35 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
232232static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
233233 assert(node->type == NodeTypeCastExpr);
234234
235 LLVMValueRef expr = gen_expr(g, node->data.cast_expr.prefix_op_expr);
235 LLVMValueRef expr_val = gen_expr(g, node->data.cast_expr.expr);
236236
237 if (!node->data.cast_expr.type)
238 return expr;
237 TypeTableEntry *actual_type = get_expr_type(node->data.cast_expr.expr);
238 TypeTableEntry *wanted_type = get_expr_type(node);
239239
240 zig_panic("TODO cast expression");
240 // this asserts are here only because no other casting codegen is supported currently
241 assert(wanted_type == g->builtin_types.entry_isize);
242
243 if (wanted_type->id == TypeTableEntryIdPointer) {
244 return LLVMBuildIntToPtr(g->builder, expr_val, wanted_type->type_ref, "");
245 } else if (wanted_type->id == TypeTableEntryIdInt) {
246 if (actual_type->size_in_bits == wanted_type->size_in_bits) {
247 if (actual_type->id == TypeTableEntryIdPointer) {
248 return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");
249 } else {
250 zig_panic("TODO gen_cast_expr");
251 }
252 } else if (actual_type->size_in_bits < wanted_type->size_in_bits) {
253 if (actual_type->data.integral.is_signed && wanted_type->data.integral.is_signed) {
254 return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, "");
255 } else {
256 zig_panic("TODO gen_cast_expr sign mismatch");
257 }
258 } else {
259 zig_panic("TODO gen_cast_expr");
260 }
261 } else {
262 zig_panic("TODO gen_cast_expr");
263 }
241264}
242265
243266static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
......@@ -610,16 +633,37 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i
610633 return return_value;
611634}
612635
636static int find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) {
637 const char *ptr = buf_ptr(&node->data.asm_expr.asm_template) + tok->start + 2;
638 int len = tok->end - tok->start - 2;
639 int result = 0;
640 for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1, result += 1) {
641 AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
642 if (buf_eql_mem(&asm_output->asm_symbolic_name, ptr, len)) {
643 return result;
644 }
645 }
646 for (int i = 0; i < node->data.asm_expr.input_list.length; i += 1, result += 1) {
647 AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
648 if (buf_eql_mem(&asm_input->asm_symbolic_name, ptr, len)) {
649 return result;
650 }
651 }
652 return -1;
653}
654
613655static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
614656 assert(node->type == NodeTypeAsmExpr);
615657
616 Buf *src_template = &node->data.asm_expr.asm_template;
658 AstNodeAsmExpr *asm_expr = &node->data.asm_expr;
659
660 Buf *src_template = &asm_expr->asm_template;
617661
618662 Buf llvm_template = BUF_INIT;
619663 buf_resize(&llvm_template, 0);
620664
621 for (int token_i = 0; token_i < node->data.asm_expr.token_list.length; token_i += 1) {
622 AsmToken *asm_token = &node->data.asm_expr.token_list.at(token_i);
665 for (int token_i = 0; token_i < asm_expr->token_list.length; token_i += 1) {
666 AsmToken *asm_token = &asm_expr->token_list.at(token_i);
623667 switch (asm_token->id) {
624668 case AsmTokenIdTemplate:
625669 for (int offset = asm_token->start; offset < asm_token->end; offset += 1) {
......@@ -634,15 +678,69 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
634678 case AsmTokenIdPercent:
635679 buf_append_char(&llvm_template, '%');
636680 break;
681 case AsmTokenIdVar:
682 int index = find_asm_index(g, node, asm_token);
683 assert(index >= 0);
684 buf_appendf(&llvm_template, "$%d", index);
685 break;
686 }
687 }
688
689 Buf constraint_buf = BUF_INIT;
690 buf_resize(&constraint_buf, 0);
691 int total_constraint_count = asm_expr->output_list.length +
692 asm_expr->input_list.length +
693 asm_expr->clobber_list.length;
694 int input_and_output_count = asm_expr->output_list.length +
695 asm_expr->input_list.length;
696 int total_index = 0;
697 LLVMTypeRef *param_types = allocate<LLVMTypeRef>(input_and_output_count);
698 LLVMValueRef *param_values = allocate<LLVMValueRef>(input_and_output_count);
699 for (int i = 0; i < asm_expr->output_list.length; i += 1, total_index += 1) {
700 AsmOutput *asm_output = asm_expr->output_list.at(i);
701 if (buf_eql_str(&asm_output->constraint, "=m")) {
702 buf_append_str(&constraint_buf, "=*m");
703 } else {
704 zig_panic("TODO unable to handle anything other than '=m' for outputs");
705 }
706 if (total_index + 1 < total_constraint_count) {
707 buf_append_char(&constraint_buf, ',');
708 }
709
710 LocalVariableTableEntry *variable = find_local_variable(
711 node->codegen_node->expr_node.block_context,
712 &asm_output->variable_name);
713 assert(variable);
714 param_types[total_index] = LLVMTypeOf(variable->value_ref);
715 param_values[total_index] = variable->value_ref;
716 }
717 for (int i = 0; i < asm_expr->input_list.length; i += 1, total_index += 1) {
718 AsmInput *asm_input = asm_expr->input_list.at(i);
719 buf_append_buf(&constraint_buf, &asm_input->constraint);
720 if (total_index + 1 < total_constraint_count) {
721 buf_append_char(&constraint_buf, ',');
722 }
723
724 TypeTableEntry *expr_type = get_expr_type(asm_input->expr);
725 param_types[total_index] = expr_type->type_ref;
726 param_values[total_index] = gen_expr(g, asm_input->expr);
727 }
728 for (int i = 0; i < asm_expr->clobber_list.length; i += 1, total_index += 1) {
729 Buf *clobber_buf = asm_expr->clobber_list.at(i);
730 buf_appendf(&constraint_buf, "~{%s}", buf_ptr(clobber_buf));
731 if (total_index + 1 < total_constraint_count) {
732 buf_append_char(&constraint_buf, ',');
637733 }
638734 }
639735
640 LLVMTypeRef function_type = LLVMFunctionType(LLVMVoidType(), nullptr, 0, false);
736 LLVMTypeRef function_type = LLVMFunctionType(LLVMVoidType(), param_types, input_and_output_count, false);
641737
642 LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template), "", true, false);
738 bool is_volatile = asm_expr->is_volatile || (asm_expr->output_list.length == 0);
739 LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template),
740 buf_ptr(&constraint_buf), is_volatile, false);
643741
644742 add_debug_source_node(g, node);
645 return LLVMBuildCall(g->builder, asm_fn, nullptr, 0, "");
743 return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");
646744}
647745
648746static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
src/parser.cpp+234-32
......@@ -245,7 +245,7 @@ void ast_print(AstNode *node, int indent) {
245245 break;
246246 case NodeTypeCastExpr:
247247 fprintf(stderr, "%s\n", node_type_str(node->type));
248 ast_print(node->data.cast_expr.prefix_op_expr, indent + 2);
248 ast_print(node->data.cast_expr.expr, indent + 2);
249249 if (node->data.cast_expr.type)
250250 ast_print(node->data.cast_expr.type, indent + 2);
251251 break;
......@@ -307,6 +307,33 @@ struct ParseContext {
307307 ErrColor err_color;
308308};
309309
310__attribute__ ((format (printf, 4, 5)))
311__attribute__ ((noreturn))
312static void ast_asm_error(ParseContext *pc, AstNode *node, int offset, const char *format, ...) {
313 assert(node->type == NodeTypeAsmExpr);
314
315 ErrorMsg *err = allocate<ErrorMsg>(1);
316
317 SrcPos pos = node->data.asm_expr.offset_map.at(offset);
318
319 err->line_start = pos.line;
320 err->column_start = pos.column;
321 err->line_end = -1;
322 err->column_end = -1;
323
324 va_list ap;
325 va_start(ap, format);
326 err->msg = buf_vprintf(format, ap);
327 va_end(ap);
328
329 err->path = pc->owner->path;
330 err->source = pc->owner->source_code;
331 err->line_offsets = pc->owner->line_offsets;
332
333 print_err_msg(err, pc->err_color);
334 exit(EXIT_FAILURE);
335}
336
310337__attribute__ ((format (printf, 3, 4)))
311338__attribute__ ((noreturn))
312339static void ast_error(ParseContext *pc, Token *token, const char *format, ...) {
......@@ -372,6 +399,7 @@ static void parse_asm_template(ParseContext *pc, AstNode *node) {
372399 StateStart,
373400 StatePercent,
374401 StateTemplate,
402 StateVar,
375403 };
376404
377405 ZigList<AsmToken> *tok_list = &node->data.asm_expr.token_list;
......@@ -403,8 +431,11 @@ static void parse_asm_template(ParseContext *pc, AstNode *node) {
403431 if (c == '%') {
404432 cur_tok->end = i;
405433 state = StateStart;
434 } else if (c == '[') {
435 cur_tok->id = AsmTokenIdVar;
436 state = StateVar;
406437 } else {
407 zig_panic("TODO handle assembly tokenize error");
438 ast_asm_error(pc, node, i, "expected a '%%' or '['");
408439 }
409440 break;
410441 case StateTemplate:
......@@ -415,6 +446,19 @@ static void parse_asm_template(ParseContext *pc, AstNode *node) {
415446 state = StateStart;
416447 }
417448 break;
449 case StateVar:
450 if (c == ']') {
451 cur_tok->end = i;
452 state = StateStart;
453 } else if ((c >= 'a' && c <= 'z') ||
454 (c >= '0' && c <= '9') ||
455 (c == '_'))
456 {
457 // do nothing
458 } else {
459 ast_asm_error(pc, node, i, "invalid substitution character: '%c'", c);
460 }
461 break;
418462 }
419463 }
420464
......@@ -422,7 +466,8 @@ static void parse_asm_template(ParseContext *pc, AstNode *node) {
422466 case StateStart:
423467 break;
424468 case StatePercent:
425 zig_panic("TODO handle assembly tokenize error eof");
469 case StateVar:
470 ast_asm_error(pc, node, buf_len(asm_template), "unexpected end of assembly template");
426471 break;
427472 case StateTemplate:
428473 cur_tok->end = buf_len(asm_template);
......@@ -430,40 +475,59 @@ static void parse_asm_template(ParseContext *pc, AstNode *node) {
430475 }
431476}
432477
433static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf) {
478static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, ZigList<SrcPos> *offset_map) {
434479 // skip the double quotes at beginning and end
435480 // convert escape sequences
436481
437482 buf_resize(buf, 0);
438483 bool escape = false;
439 for (int i = token->start_pos + 1; i < token->end_pos - 1; i += 1) {
484 bool first = true;
485 SrcPos pos = {token->start_line, token->start_column};
486 for (int i = token->start_pos; i < token->end_pos - 1; i += 1) {
440487 uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + i);
441 if (escape) {
442 switch (c) {
443 case '\\':
444 buf_append_char(buf, '\\');
445 break;
446 case 'r':
447 buf_append_char(buf, '\r');
448 break;
449 case 'n':
450 buf_append_char(buf, '\n');
451 break;
452 case 't':
453 buf_append_char(buf, '\t');
454 break;
455 case '"':
456 buf_append_char(buf, '"');
457 break;
488 if (first) {
489 first = false;
490 } else {
491 if (escape) {
492 switch (c) {
493 case '\\':
494 buf_append_char(buf, '\\');
495 if (offset_map) offset_map->append(pos);
496 break;
497 case 'r':
498 buf_append_char(buf, '\r');
499 if (offset_map) offset_map->append(pos);
500 break;
501 case 'n':
502 buf_append_char(buf, '\n');
503 if (offset_map) offset_map->append(pos);
504 break;
505 case 't':
506 buf_append_char(buf, '\t');
507 if (offset_map) offset_map->append(pos);
508 break;
509 case '"':
510 buf_append_char(buf, '"');
511 if (offset_map) offset_map->append(pos);
512 break;
513 }
514 escape = false;
515 } else if (c == '\\') {
516 escape = true;
517 } else {
518 buf_append_char(buf, c);
519 if (offset_map) offset_map->append(pos);
458520 }
459 escape = false;
460 } else if (c == '\\') {
461 escape = true;
521 }
522 if (c == '\n') {
523 pos.line += 1;
524 pos.column = 0;
462525 } else {
463 buf_append_char(buf, c);
526 pos.column += 1;
464527 }
465528 }
466529 assert(!escape);
530 if (offset_map) offset_map->append(pos);
467531}
468532
469533__attribute__ ((noreturn))
......@@ -505,7 +569,7 @@ static AstNode *ast_parse_directive(ParseContext *pc, int token_index, int *new_
505569 token_index += 1;
506570 ast_expect_token(pc, param_str, TokenIdStringLiteral);
507571
508 parse_string_literal(pc, param_str, &node->data.directive.param);
572 parse_string_literal(pc, param_str, &node->data.directive.param, nullptr);
509573
510574 Token *r_paren = &pc->tokens->at(token_index);
511575 token_index += 1;
......@@ -718,7 +782,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
718782 return node;
719783 } else if (token->id == TokenIdStringLiteral) {
720784 AstNode *node = ast_create_node(pc, NodeTypeStringLiteral, token);
721 parse_string_literal(pc, token, &node->data.string);
785 parse_string_literal(pc, token, &node->data.string, nullptr);
722786 *token_index += 1;
723787 return node;
724788 } else if (token->id == TokenIdKeywordUnreachable) {
......@@ -861,7 +925,7 @@ static AstNode *ast_parse_cast_expression(ParseContext *pc, int *token_index, bo
861925 *token_index += 1;
862926
863927 AstNode *node = ast_create_node(pc, NodeTypeCastExpr, as_kw);
864 node->data.cast_expr.prefix_op_expr = prefix_op_expr;
928 node->data.cast_expr.expr = prefix_op_expr;
865929
866930 node->data.cast_expr.type = ast_parse_type(pc, *token_index, token_index);
867931
......@@ -1333,6 +1397,141 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mand
13331397 return node;
13341398}
13351399
1400static Token *ast_eat_token(ParseContext *pc, int *token_index, TokenId token_id) {
1401 Token *token = &pc->tokens->at(*token_index);
1402 ast_expect_token(pc, token, token_id);
1403 *token_index += 1;
1404 return token;
1405}
1406
1407
1408/*
1409AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen)
1410*/
1411static void ast_parse_asm_input_item(ParseContext *pc, int *token_index, AstNode *node) {
1412 ast_eat_token(pc, token_index, TokenIdLBracket);
1413 Token *alias = ast_eat_token(pc, token_index, TokenIdSymbol);
1414 ast_eat_token(pc, token_index, TokenIdRBracket);
1415
1416 Token *constraint = ast_eat_token(pc, token_index, TokenIdStringLiteral);
1417
1418 ast_eat_token(pc, token_index, TokenIdLParen);
1419 AstNode *expr_node = ast_parse_expression(pc, token_index, true);
1420 ast_eat_token(pc, token_index, TokenIdRParen);
1421
1422 AsmInput *asm_input = allocate<AsmInput>(1);
1423 ast_buf_from_token(pc, alias, &asm_input->asm_symbolic_name);
1424 parse_string_literal(pc, constraint, &asm_input->constraint, nullptr);
1425 asm_input->expr = expr_node;
1426 node->data.asm_expr.input_list.append(asm_input);
1427}
1428
1429/*
1430AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) token(Symbol) token(RParen)
1431*/
1432static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNode *node) {
1433 ast_eat_token(pc, token_index, TokenIdLBracket);
1434 Token *alias = ast_eat_token(pc, token_index, TokenIdSymbol);
1435 ast_eat_token(pc, token_index, TokenIdRBracket);
1436
1437 Token *constraint = ast_eat_token(pc, token_index, TokenIdStringLiteral);
1438
1439 ast_eat_token(pc, token_index, TokenIdLParen);
1440 Token *out_symbol = ast_eat_token(pc, token_index, TokenIdSymbol);
1441 ast_eat_token(pc, token_index, TokenIdRParen);
1442
1443 AsmOutput *asm_output = allocate<AsmOutput>(1);
1444 ast_buf_from_token(pc, alias, &asm_output->asm_symbolic_name);
1445 parse_string_literal(pc, constraint, &asm_output->constraint, nullptr);
1446 ast_buf_from_token(pc, out_symbol, &asm_output->variable_name);
1447 node->data.asm_expr.output_list.append(asm_output);
1448}
1449
1450/*
1451AsmClobbers: token(Colon) list(token(String), token(Comma))
1452*/
1453static void ast_parse_asm_clobbers(ParseContext *pc, int *token_index, AstNode *node) {
1454 Token *colon_tok = &pc->tokens->at(*token_index);
1455
1456 if (colon_tok->id != TokenIdColon)
1457 return;
1458
1459 *token_index += 1;
1460
1461 for (;;) {
1462 Token *string_tok = &pc->tokens->at(*token_index);
1463 ast_expect_token(pc, string_tok, TokenIdStringLiteral);
1464 *token_index += 1;
1465
1466 Buf *clobber_buf = buf_alloc();
1467 parse_string_literal(pc, string_tok, clobber_buf, nullptr);
1468 node->data.asm_expr.clobber_list.append(clobber_buf);
1469
1470 Token *comma = &pc->tokens->at(*token_index);
1471
1472 if (comma->id == TokenIdComma) {
1473 *token_index += 1;
1474 continue;
1475 } else {
1476 break;
1477 }
1478 }
1479}
1480
1481/*
1482AsmInput : token(Colon) list(AsmInputItem, token(Comma)) option(AsmClobbers)
1483*/
1484static void ast_parse_asm_input(ParseContext *pc, int *token_index, AstNode *node) {
1485 Token *colon_tok = &pc->tokens->at(*token_index);
1486
1487 if (colon_tok->id != TokenIdColon)
1488 return;
1489
1490 *token_index += 1;
1491
1492 for (;;) {
1493 ast_parse_asm_input_item(pc, token_index, node);
1494
1495 Token *comma = &pc->tokens->at(*token_index);
1496
1497 if (comma->id == TokenIdComma) {
1498 *token_index += 1;
1499 continue;
1500 } else {
1501 break;
1502 }
1503 }
1504
1505 ast_parse_asm_clobbers(pc, token_index, node);
1506}
1507
1508/*
1509AsmOutput : token(Colon) list(AsmOutputItem, token(Comma)) option(AsmInput)
1510*/
1511static void ast_parse_asm_output(ParseContext *pc, int *token_index, AstNode *node) {
1512 Token *colon_tok = &pc->tokens->at(*token_index);
1513
1514 if (colon_tok->id != TokenIdColon)
1515 return;
1516
1517 *token_index += 1;
1518
1519 for (;;) {
1520 ast_parse_asm_output_item(pc, token_index, node);
1521
1522 Token *comma = &pc->tokens->at(*token_index);
1523
1524 if (comma->id == TokenIdComma) {
1525 *token_index += 1;
1526 continue;
1527 } else {
1528 break;
1529 }
1530 }
1531
1532 ast_parse_asm_input(pc, token_index, node);
1533}
1534
13361535/*
13371536AsmExpression : token(Asm) option(token(Volatile)) token(LParen) token(String) option(AsmOutput) token(RParen)
13381537*/
......@@ -1366,9 +1565,12 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand
13661565 ast_expect_token(pc, template_tok, TokenIdStringLiteral);
13671566 *token_index += 1;
13681567
1369 parse_string_literal(pc, template_tok, &node->data.asm_expr.asm_template);
1568 parse_string_literal(pc, template_tok, &node->data.asm_expr.asm_template,
1569 &node->data.asm_expr.offset_map);
13701570 parse_asm_template(pc, node);
13711571
1572 ast_parse_asm_output(pc, token_index, node);
1573
13721574 Token *rparen_tok = &pc->tokens->at(*token_index);
13731575 ast_expect_token(pc, rparen_tok, TokenIdRParen);
13741576 *token_index += 1;
......@@ -1675,7 +1877,7 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b
16751877 *token_index += 1;
16761878 ast_expect_token(pc, export_name, TokenIdStringLiteral);
16771879
1678 parse_string_literal(pc, export_name, &node->data.root_export_decl.name);
1880 parse_string_literal(pc, export_name, &node->data.root_export_decl.name, nullptr);
16791881
16801882 Token *semicolon = &pc->tokens->at(*token_index);
16811883 *token_index += 1;
......@@ -1705,7 +1907,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory
17051907
17061908 AstNode *node = ast_create_node(pc, NodeTypeUse, use_kw);
17071909
1708 parse_string_literal(pc, use_name, &node->data.use.path);
1910 parse_string_literal(pc, use_name, &node->data.use.path, nullptr);
17091911
17101912 node->data.use.directives = pc->directive_list;
17111913 pc->directive_list = nullptr;
src/parser.hpp+23-2
......@@ -169,8 +169,7 @@ struct AstNodeRootExportDecl {
169169};
170170
171171struct AstNodeCastExpr {
172 AstNode *prefix_op_expr;
173 // if type is non-null, do cast, otherwise nothing
172 AstNode *expr;
174173 AstNode *type;
175174};
176175
......@@ -205,10 +204,31 @@ struct AstNodeGoto {
205204 Buf name;
206205};
207206
207struct AsmOutput {
208 Buf asm_symbolic_name;
209 Buf constraint;
210 Buf variable_name;
211};
212
213struct AsmInput {
214 Buf asm_symbolic_name;
215 Buf constraint;
216 AstNode *expr;
217};
218
219struct SrcPos {
220 int line;
221 int column;
222};
223
208224struct AstNodeAsmExpr {
209225 bool is_volatile;
210226 Buf asm_template;
227 ZigList<SrcPos> offset_map;
211228 ZigList<AsmToken> token_list;
229 ZigList<AsmOutput*> output_list;
230 ZigList<AsmInput*> input_list;
231 ZigList<Buf*> clobber_list;
212232};
213233
214234struct AstNode {
......@@ -250,6 +270,7 @@ struct AstNode {
250270enum AsmTokenId {
251271 AsmTokenIdTemplate,
252272 AsmTokenIdPercent,
273 AsmTokenIdVar,
253274};
254275
255276struct AsmToken {
std/std.zig+11-10
......@@ -1,13 +1,13 @@
11fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
22 let mut result : isize;
3 asm volatile (
4 "mov %[number], %%rax\n"
5 "mov %[arg1], %%rdi\n"
6 "mov %[arg2], %%rsi\n"
7 "mov %[arg3], %%rdx\n"
8 "syscall\n"
9 "mov %%rax, %[ret]\n"
10 : [ret] "=r" (result)
3 asm volatile ("
4 mov %[number], %%rax
5 mov %[arg1], %%rdi
6 mov %[arg2], %%rsi
7 mov %[arg3], %%rdx
8 syscall
9 mov %%rax, %[ret]"
10 : [ret] "=m" (result)
1111 : [number] "r" (number), [arg1] "r" (arg1), [arg2] "r" (arg2), [arg3] "r" (arg3)
1212 : "rcx", "r11", "rax", "rdi", "rsi", "rdx");
1313 return result;
......@@ -16,8 +16,9 @@ fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
1616// TODO error handling
1717// TODO zig strings instead of C strings
1818// TODO handle buffering and flushing
19pub print_str(str : *const u8, len: isize) {
19// TODO non-i32 integer literals so we can remove the casts
20pub fn print_str(str : *const u8, len: isize) {
2021 let SYS_write = 1;
2122 let stdout_fileno = 1;
22 syscall3(SYS_write, stdout_fileno, str as isize, str_len);
23 syscall3(SYS_write as isize, stdout_fileno as isize, str as isize, len);
2324}
test/run_tests.cpp+12
......@@ -398,6 +398,18 @@ loop_2_end:
398398}
399399 )SOURCE", "OK\n");
400400
401
402 add_simple_case("hello world without libc", R"SOURCE(
403use "std.zig";
404
405export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
406 print_str("Hello, world!\n", 14 as isize);
407 return 0;
408}
409 )SOURCE", "Hello, world!\n");
410
411
412
401413}
402414
403415static void add_compile_failure_test_cases(void) {