From ea60db9f53e9f8d4f3456a6e8eb813a9949a69d3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 6 Dec 2020 01:14:55 +0000 Subject: [PATCH] Add inline asm expression to odin/parser --- core/odin/ast/ast.odin | 21 +++++++++ core/odin/parser/parser.odin | 84 ++++++++++++++++++++++++++++++++++ core/odin/tokenizer/token.odin | 2 + 3 files changed, 107 insertions(+) diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index 990e7b47e..36791b11e 100644 --- a/core/odin/ast/ast.odin +++ b/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, +} + diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index d092c8740..2d8f31cbb 100644 --- a/core/odin/parser/parser.odin +++ b/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(¶m_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; diff --git a/core/odin/tokenizer/token.odin b/core/odin/tokenizer/token.odin index 997b4967d..169aca72b 100644 --- a/core/odin/tokenizer/token.odin +++ b/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", "", };