瀏覽代碼

Add inline asm expression to odin/parser

gingerBill 4 年之前
父節點
當前提交
ea60db9f53
共有 3 個文件被更改,包括 107 次插入0 次删除
  1. 21 0
      core/odin/ast/ast.odin
  2. 84 0
      core/odin/parser/parser.odin
  3. 2 0
      core/odin/tokenizer/token.odin

+ 21 - 0
core/odin/ast/ast.odin

@@ -254,6 +254,27 @@ Auto_Cast :: struct {
 	expr: ^Expr,
 }
 
+Inline_Asm_Dialect :: enum u8 {
+	Default = 0,
+	ATT     = 1,
+	Intel   = 2,
+}
+
+
+Inline_Asm_Expr :: struct {
+	using node: Expr,
+	tok:                tokenizer.Token,
+	param_types:        []^Expr,
+	return_type:        ^Expr,
+	constraints_string: ^Expr,
+	has_side_effects:   bool,
+	is_align_stack:     bool,
+	dialect:            Inline_Asm_Dialect,
+	open:               tokenizer.Pos,
+	asm_string:         ^Expr,
+	close:              tokenizer.Pos,
+}
+
 
 
 

+ 84 - 0
core/odin/parser/parser.odin

@@ -1040,6 +1040,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
 	case .Context, // Also allows for 'context = '
 	     .Proc,
 	     .Inline, .No_Inline,
+	     .Asm, // Inline assembly
 	     .Ident,
 	     .Integer, .Float, .Imag,
 	     .Rune, .String,
@@ -2595,6 +2596,89 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
 		bst.close = close.pos;
 		return bst;
 
+	case .Asm:
+		tok := expect_token(p, .Asm);
+
+		param_types: [dynamic]^ast.Expr
+		return_type: ^ast.Expr;
+		if allow_token(p, .Open_Paren) {
+			for p.curr_tok.kind != .Close_Paren && p.curr_tok.kind != .EOF {
+				t := parse_type(p);
+				append(&param_types, t);
+				if p.curr_tok.kind != .Comma ||
+				   p.curr_tok.kind == .EOF {
+					break;
+				}
+				advance_token(p);
+			}
+			expect_token(p, .Close_Paren);
+
+			if allow_token(p, .Arrow_Right) {
+				return_type = parse_type(p);
+			}
+		}
+
+		has_side_effects := false;
+		is_align_stack := false;
+		dialect := ast.Inline_Asm_Dialect.Default;
+		for allow_token(p, .Hash) {
+			if p.curr_tok.kind == .Ident {
+				name := advance_token(p);
+				switch name.text {
+				case "side_effects":
+					if has_side_effects {
+						error(p, tok.pos, "duplicate directive on inline asm expression: '#side_effects'");
+					}
+					has_side_effects = true;
+				case "align_stack":
+					if is_align_stack {
+						error(p, tok.pos, "duplicate directive on inline asm expression: '#align_stack'");
+					}
+					is_align_stack = true;
+				case "att":
+					if dialect == .ATT {
+						error(p, tok.pos, "duplicate directive on inline asm expression: '#att'");
+					} else if dialect != .Default {
+						error(p, tok.pos, "conflicting asm dialects");
+					} else {
+						dialect = .ATT;
+					}
+				case "intel":
+					if dialect == .Intel {
+						error(p, tok.pos, "duplicate directive on inline asm expression: '#intel'");
+					} else if dialect != .Default {
+						error(p, tok.pos, "conflicting asm dialects");
+					} else {
+						dialect = .Intel;
+					}
+				}
+
+			} else {
+				error(p, p.curr_tok.pos, "expected an identifier after hash");
+			}
+		}
+
+		open := expect_token(p, .Open_Brace);
+		asm_string := parse_expr(p, false);
+		expect_token(p, .Comma);
+		constraints_string := parse_expr(p, false);
+		allow_token(p, .Comma);
+		close := expect_token(p, .Close_Brace);
+
+		e := ast.new(ast.Inline_Asm_Expr, tok.pos, end_pos(close));
+		e.tok                = tok;
+		e.param_types        = param_types[:];
+		e.return_type        = return_type;
+		e.constraints_string = constraints_string;
+		e.has_side_effects   = has_side_effects;
+		e.is_align_stack     = is_align_stack;
+		e.dialect            = dialect;
+		e.open               = open.pos;
+		e.asm_string         = asm_string;
+		e.close              = close.pos;
+
+		return e;
+
 	}
 
 	return nil;

+ 2 - 0
core/odin/tokenizer/token.odin

@@ -149,6 +149,7 @@ Token_Kind :: enum u32 {
 		Inline,
 		No_Inline,
 		Context,
+		Asm,
 	B_Keyword_End,
 
 	COUNT,
@@ -278,6 +279,7 @@ tokens := [Token_Kind.COUNT]string {
 	"inline",
 	"no_inline",
 	"context",
+	"asm",
 	"",
 };