From ccc7f9987debd2112d1432f7aa58a81a0814e81d Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Thu, 2 Sep 2021 14:45:00 +0200 Subject: [PATCH] Address spaces: addrspace(A) parsing The grammar for function prototypes, (global) variable declarations, and pointer types now accepts an optional addrspace(A) modifier. --- lib/std/zig/Ast.zig | 54 +++++++++++++++++-- lib/std/zig/parse.zig | 107 +++++++++++++++++++++++++++++--------- lib/std/zig/tokenizer.zig | 3 ++ src/translate_c/ast.zig | 1 + 4 files changed, 135 insertions(+), 30 deletions(-) diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig index 35e75f4db28e..a62e9c105d8e 100644 --- a/lib/std/zig/Ast.zig +++ b/lib/std/zig/Ast.zig @@ -262,6 +262,9 @@ pub fn renderError(tree: Tree, parse_error: Error, stream: anytype) !void { token_tags[parse_error.token].symbol(), }); }, + .extra_addrspace_qualifier => { + return stream.writeAll("extra addrspace qualifier"); + }, .extra_align_qualifier => { return stream.writeAll("extra align qualifier"); }, @@ -1021,7 +1024,7 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex { }, .fn_proto_one => { const extra = tree.extraData(datas[n].lhs, Node.FnProtoOne); - // linksection, callconv, align can appear in any order, so we + // addrspace, linksection, callconv, align can appear in any order, so we // find the last one here. var max_node: Node.Index = datas[n].rhs; var max_start = token_starts[main_tokens[max_node]]; @@ -1034,6 +1037,14 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex { max_offset = 1; // for the rparen } } + if (extra.addrspace_expr != 0) { + const start = token_starts[main_tokens[extra.addrspace_expr]]; + if (start > max_start) { + max_node = extra.addrspace_expr; + max_start = start; + max_offset = 1; // for the rparen + } + } if (extra.section_expr != 0) { const start = token_starts[main_tokens[extra.section_expr]]; if (start > max_start) { @@ -1055,7 +1066,7 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex { }, .fn_proto => { const extra = tree.extraData(datas[n].lhs, Node.FnProto); - // linksection, callconv, align can appear in any order, so we + // addrspace, linksection, callconv, align can appear in any order, so we // find the last one here. var max_node: Node.Index = datas[n].rhs; var max_start = token_starts[main_tokens[max_node]]; @@ -1068,6 +1079,14 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex { max_offset = 1; // for the rparen } } + if (extra.addrspace_expr != 0) { + const start = token_starts[main_tokens[extra.addrspace_expr]]; + if (start > max_start) { + max_node = extra.addrspace_expr; + max_start = start; + max_offset = 1; // for the rparen + } + } if (extra.section_expr != 0) { const start = token_starts[main_tokens[extra.section_expr]]; if (start > max_start) { @@ -1138,6 +1157,7 @@ pub fn globalVarDecl(tree: Tree, node: Node.Index) full.VarDecl { return tree.fullVarDecl(.{ .type_node = extra.type_node, .align_node = extra.align_node, + .addrspace_node = extra.addrspace_node, .section_node = extra.section_node, .init_node = data.rhs, .mut_token = tree.nodes.items(.main_token)[node], @@ -1151,6 +1171,7 @@ pub fn localVarDecl(tree: Tree, node: Node.Index) full.VarDecl { return tree.fullVarDecl(.{ .type_node = extra.type_node, .align_node = extra.align_node, + .addrspace_node = 0, .section_node = 0, .init_node = data.rhs, .mut_token = tree.nodes.items(.main_token)[node], @@ -1163,6 +1184,7 @@ pub fn simpleVarDecl(tree: Tree, node: Node.Index) full.VarDecl { return tree.fullVarDecl(.{ .type_node = data.lhs, .align_node = 0, + .addrspace_node = 0, .section_node = 0, .init_node = data.rhs, .mut_token = tree.nodes.items(.main_token)[node], @@ -1175,6 +1197,7 @@ pub fn alignedVarDecl(tree: Tree, node: Node.Index) full.VarDecl { return tree.fullVarDecl(.{ .type_node = 0, .align_node = data.lhs, + .addrspace_node = 0, .section_node = 0, .init_node = data.rhs, .mut_token = tree.nodes.items(.main_token)[node], @@ -1249,6 +1272,7 @@ pub fn fnProtoSimple(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full. .return_type = data.rhs, .params = params, .align_expr = 0, + .addrspace_expr = 0, .section_expr = 0, .callconv_expr = 0, }); @@ -1265,6 +1289,7 @@ pub fn fnProtoMulti(tree: Tree, node: Node.Index) full.FnProto { .return_type = data.rhs, .params = params, .align_expr = 0, + .addrspace_expr = 0, .section_expr = 0, .callconv_expr = 0, }); @@ -1282,6 +1307,7 @@ pub fn fnProtoOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.FnP .return_type = data.rhs, .params = params, .align_expr = extra.align_expr, + .addrspace_expr = extra.addrspace_expr, .section_expr = extra.section_expr, .callconv_expr = extra.callconv_expr, }); @@ -1298,6 +1324,7 @@ pub fn fnProto(tree: Tree, node: Node.Index) full.FnProto { .return_type = data.rhs, .params = params, .align_expr = extra.align_expr, + .addrspace_expr = extra.addrspace_expr, .section_expr = extra.section_expr, .callconv_expr = extra.callconv_expr, }); @@ -1453,6 +1480,7 @@ pub fn ptrTypeAligned(tree: Tree, node: Node.Index) full.PtrType { return tree.fullPtrType(.{ .main_token = tree.nodes.items(.main_token)[node], .align_node = data.lhs, + .addrspace_node = 0, .sentinel = 0, .bit_range_start = 0, .bit_range_end = 0, @@ -1466,6 +1494,7 @@ pub fn ptrTypeSentinel(tree: Tree, node: Node.Index) full.PtrType { return tree.fullPtrType(.{ .main_token = tree.nodes.items(.main_token)[node], .align_node = 0, + .addrspace_node = 0, .sentinel = data.lhs, .bit_range_start = 0, .bit_range_end = 0, @@ -1480,6 +1509,7 @@ pub fn ptrType(tree: Tree, node: Node.Index) full.PtrType { return tree.fullPtrType(.{ .main_token = tree.nodes.items(.main_token)[node], .align_node = extra.align_node, + .addrspace_node = extra.addrspace_node, .sentinel = extra.sentinel, .bit_range_start = 0, .bit_range_end = 0, @@ -1494,6 +1524,7 @@ pub fn ptrTypeBitRange(tree: Tree, node: Node.Index) full.PtrType { return tree.fullPtrType(.{ .main_token = tree.nodes.items(.main_token)[node], .align_node = extra.align_node, + .addrspace_node = extra.addrspace_node, .sentinel = extra.sentinel, .bit_range_start = extra.bit_range_start, .bit_range_end = extra.bit_range_end, @@ -2063,6 +2094,7 @@ pub const full = struct { mut_token: TokenIndex, type_node: Node.Index, align_node: Node.Index, + addrspace_node: Node.Index, section_node: Node.Index, init_node: Node.Index, }; @@ -2130,6 +2162,7 @@ pub const full = struct { return_type: Node.Index, params: []const Node.Index, align_expr: Node.Index, + addrspace_expr: Node.Index, section_expr: Node.Index, callconv_expr: Node.Index, }; @@ -2288,6 +2321,7 @@ pub const full = struct { pub const Components = struct { main_token: TokenIndex, align_node: Node.Index, + addrspace_node: Node.Index, sentinel: Node.Index, bit_range_start: Node.Index, bit_range_end: Node.Index, @@ -2397,6 +2431,7 @@ pub const Error = struct { expected_var_decl_or_fn, expected_loop_payload, expected_container, + extra_addrspace_qualifier, extra_align_qualifier, extra_allowzero_qualifier, extra_const_qualifier, @@ -2723,13 +2758,13 @@ pub const Node = struct { /// main_token is the `fn` keyword. /// extern function declarations use this tag. fn_proto_multi, - /// `fn(a: b) rhs linksection(e) callconv(f)`. `FnProtoOne[lhs]`. + /// `fn(a: b) rhs addrspace(e) linksection(f) callconv(g)`. `FnProtoOne[lhs]`. /// zero or one parameters. /// anytype and ... parameters are omitted from the AST tree. /// main_token is the `fn` keyword. /// extern function declarations use this tag. fn_proto_one, - /// `fn(a: b, c: d) rhs linksection(e) callconv(f)`. `FnProto[lhs]`. + /// `fn(a: b, c: d) rhs addrspace(e) linksection(f) callconv(g)`. `FnProto[lhs]`. /// anytype and ... parameters are omitted from the AST tree. /// main_token is the `fn` keyword. /// extern function declarations use this tag. @@ -2893,11 +2928,13 @@ pub const Node = struct { pub const PtrType = struct { sentinel: Index, align_node: Index, + addrspace_node: Index, }; pub const PtrTypeBitRange = struct { sentinel: Index, align_node: Index, + addrspace_node: Index, bit_range_start: Index, bit_range_end: Index, }; @@ -2920,8 +2957,13 @@ pub const Node = struct { }; pub const GlobalVarDecl = struct { + /// Populated if there is an explicit type ascription. type_node: Index, + /// Populated if align(A) is present. align_node: Index, + /// Populated if linksection(A) is present. + addrspace_node: Index, + /// Populated if addrspace(A) is present. section_node: Index, }; @@ -2954,6 +2996,8 @@ pub const Node = struct { /// Populated if align(A) is present. align_expr: Index, /// Populated if linksection(A) is present. + addrspace_expr: Index, + /// Populated if addrspace(A) is present. section_expr: Index, /// Populated if callconv(A) is present. callconv_expr: Index, @@ -2964,6 +3008,8 @@ pub const Node = struct { params_end: Index, /// Populated if align(A) is present. align_expr: Index, + /// Populated if addrspace(A) is present. + addrspace_expr: Index, /// Populated if linksection(A) is present. section_expr: Index, /// Populated if callconv(A) is present. diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index 5bd5a6dfebdf..f7697027a3e6 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -629,7 +629,7 @@ const Parser = struct { }; } - /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr + /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr fn parseFnProto(p: *Parser) !Node.Index { const fn_token = p.eatToken(.keyword_fn) orelse return null_node; @@ -639,6 +639,7 @@ const Parser = struct { _ = p.eatToken(.identifier); const params = try p.parseParamDeclList(); const align_expr = try p.parseByteAlign(); + const addrspace_expr = try p.parseAddrSpace(); const section_expr = try p.parseLinkSection(); const callconv_expr = try p.parseCallconv(); _ = p.eatToken(.bang); @@ -650,7 +651,7 @@ const Parser = struct { try p.warn(.expected_return_type); } - if (align_expr == 0 and section_expr == 0 and callconv_expr == 0) { + if (align_expr == 0 and section_expr == 0 and callconv_expr == 0 and addrspace_expr == 0) { switch (params) { .zero_or_one => |param| return p.setNode(fn_proto_index, .{ .tag = .fn_proto_simple, @@ -683,6 +684,7 @@ const Parser = struct { .lhs = try p.addExtra(Node.FnProtoOne{ .param = param, .align_expr = align_expr, + .addrspace_expr = addrspace_expr, .section_expr = section_expr, .callconv_expr = callconv_expr, }), @@ -698,6 +700,7 @@ const Parser = struct { .params_start = span.start, .params_end = span.end, .align_expr = align_expr, + .addrspace_expr = addrspace_expr, .section_expr = section_expr, .callconv_expr = callconv_expr, }), @@ -708,7 +711,7 @@ const Parser = struct { } } - /// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON + /// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection? (EQUAL Expr)? SEMICOLON fn parseVarDecl(p: *Parser) !Node.Index { const mut_token = p.eatToken(.keyword_const) orelse p.eatToken(.keyword_var) orelse @@ -717,9 +720,10 @@ const Parser = struct { _ = try p.expectToken(.identifier); const type_node: Node.Index = if (p.eatToken(.colon) == null) 0 else try p.expectTypeExpr(); const align_node = try p.parseByteAlign(); + const addrspace_node = try p.parseAddrSpace(); const section_node = try p.parseLinkSection(); const init_node: Node.Index = if (p.eatToken(.equal) == null) 0 else try p.expectExpr(); - if (section_node == 0) { + if (section_node == 0 and addrspace_node == 0) { if (align_node == 0) { return p.addNode(.{ .tag = .simple_var_decl, @@ -759,6 +763,7 @@ const Parser = struct { .lhs = try p.addExtra(Node.GlobalVarDecl{ .type_node = type_node, .align_node = align_node, + .addrspace_node = addrspace_node, .section_node = section_node, }), .rhs = init_node, @@ -1440,8 +1445,8 @@ const Parser = struct { /// PrefixTypeOp /// <- QUESTIONMARK /// / KEYWORD_anyframe MINUSRARROW - /// / SliceTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* - /// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* + /// / SliceTypeStart (ByteAlign / AddrSpace / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* + /// / PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* /// / ArrayTypeStart /// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET /// PtrTypeStart @@ -1474,29 +1479,43 @@ const Parser = struct { const asterisk = p.nextToken(); const mods = try p.parsePtrModifiers(); const elem_type = try p.expectTypeExpr(); - if (mods.bit_range_start == 0) { + if (mods.bit_range_start != 0) { return p.addNode(.{ - .tag = .ptr_type_aligned, + .tag = .ptr_type_bit_range, .main_token = asterisk, .data = .{ - .lhs = mods.align_node, + .lhs = try p.addExtra(Node.PtrTypeBitRange{ + .sentinel = 0, + .align_node = mods.align_node, + .addrspace_node = mods.addrspace_node, + .bit_range_start = mods.bit_range_start, + .bit_range_end = mods.bit_range_end, + }), .rhs = elem_type, }, }); - } else { + } else if (mods.addrspace_node != 0) { return p.addNode(.{ - .tag = .ptr_type_bit_range, + .tag = .ptr_type, .main_token = asterisk, .data = .{ - .lhs = try p.addExtra(Node.PtrTypeBitRange{ + .lhs = try p.addExtra(Node.PtrType{ .sentinel = 0, .align_node = mods.align_node, - .bit_range_start = mods.bit_range_start, - .bit_range_end = mods.bit_range_end, + .addrspace_node = mods.addrspace_node, }), .rhs = elem_type, }, }); + } else { + return p.addNode(.{ + .tag = .ptr_type_aligned, + .main_token = asterisk, + .data = .{ + .lhs = mods.align_node, + .rhs = elem_type, + }, + }); } }, .asterisk_asterisk => { @@ -1504,29 +1523,43 @@ const Parser = struct { const mods = try p.parsePtrModifiers(); const elem_type = try p.expectTypeExpr(); const inner: Node.Index = inner: { - if (mods.bit_range_start == 0) { + if (mods.bit_range_start != 0) { break :inner try p.addNode(.{ - .tag = .ptr_type_aligned, + .tag = .ptr_type_bit_range, .main_token = asterisk, .data = .{ - .lhs = mods.align_node, + .lhs = try p.addExtra(Node.PtrTypeBitRange{ + .sentinel = 0, + .align_node = mods.align_node, + .addrspace_node = mods.addrspace_node, + .bit_range_start = mods.bit_range_start, + .bit_range_end = mods.bit_range_end, + }), .rhs = elem_type, }, }); - } else { + } else if (mods.addrspace_node != 0) { break :inner try p.addNode(.{ - .tag = .ptr_type_bit_range, + .tag = .ptr_type, .main_token = asterisk, .data = .{ - .lhs = try p.addExtra(Node.PtrTypeBitRange{ + .lhs = try p.addExtra(Node.PtrType{ .sentinel = 0, .align_node = mods.align_node, - .bit_range_start = mods.bit_range_start, - .bit_range_end = mods.bit_range_end, + .addrspace_node = mods.addrspace_node, }), .rhs = elem_type, }, }); + } else { + break :inner try p.addNode(.{ + .tag = .ptr_type_aligned, + .main_token = asterisk, + .data = .{ + .lhs = mods.align_node, + .rhs = elem_type, + }, + }); } }; return p.addNode(.{ @@ -1560,7 +1593,7 @@ const Parser = struct { const mods = try p.parsePtrModifiers(); const elem_type = try p.expectTypeExpr(); if (mods.bit_range_start == 0) { - if (sentinel == 0) { + if (sentinel == 0 and mods.addrspace_node == 0) { return p.addNode(.{ .tag = .ptr_type_aligned, .main_token = asterisk, @@ -1569,7 +1602,7 @@ const Parser = struct { .rhs = elem_type, }, }); - } else if (mods.align_node == 0) { + } else if (mods.align_node == 0 and mods.addrspace_node == 0) { return p.addNode(.{ .tag = .ptr_type_sentinel, .main_token = asterisk, @@ -1586,6 +1619,7 @@ const Parser = struct { .lhs = try p.addExtra(Node.PtrType{ .sentinel = sentinel, .align_node = mods.align_node, + .addrspace_node = mods.addrspace_node, }), .rhs = elem_type, }, @@ -1599,6 +1633,7 @@ const Parser = struct { .lhs = try p.addExtra(Node.PtrTypeBitRange{ .sentinel = sentinel, .align_node = mods.align_node, + .addrspace_node = mods.addrspace_node, .bit_range_start = mods.bit_range_start, .bit_range_end = mods.bit_range_end, }), @@ -1624,7 +1659,7 @@ const Parser = struct { .token = p.nodes.items(.main_token)[mods.bit_range_start], }); } - if (sentinel == 0) { + if (sentinel == 0 and mods.addrspace_node == 0) { return p.addNode(.{ .tag = .ptr_type_aligned, .main_token = lbracket, @@ -1633,7 +1668,7 @@ const Parser = struct { .rhs = elem_type, }, }); - } else if (mods.align_node == 0) { + } else if (mods.align_node == 0 and mods.addrspace_node == 0) { return p.addNode(.{ .tag = .ptr_type_sentinel, .main_token = lbracket, @@ -1650,6 +1685,7 @@ const Parser = struct { .lhs = try p.addExtra(Node.PtrType{ .sentinel = sentinel, .align_node = mods.align_node, + .addrspace_node = mods.addrspace_node, }), .rhs = elem_type, }, @@ -1661,6 +1697,7 @@ const Parser = struct { .keyword_const, .keyword_volatile, .keyword_allowzero, + .keyword_addrspace, => return p.fail(.ptr_mod_on_array_child_type), else => {}, } @@ -2879,6 +2916,15 @@ const Parser = struct { return expr_node; } + /// AddrSpace <- KEYWORD_addrspace LPAREN Expr RPAREN + fn parseAddrSpace(p: *Parser) !Node.Index { + _ = p.eatToken(.keyword_addrspace) orelse return null_node; + _ = try p.expectToken(.l_paren); + const expr_node = try p.expectExpr(); + _ = try p.expectToken(.r_paren); + return expr_node; + } + /// ParamDecl /// <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType /// / DOT3 @@ -3011,6 +3057,7 @@ const Parser = struct { const PtrModifiers = struct { align_node: Node.Index, + addrspace_node: Node.Index, bit_range_start: Node.Index, bit_range_end: Node.Index, }; @@ -3018,12 +3065,14 @@ const Parser = struct { fn parsePtrModifiers(p: *Parser) !PtrModifiers { var result: PtrModifiers = .{ .align_node = 0, + .addrspace_node = 0, .bit_range_start = 0, .bit_range_end = 0, }; var saw_const = false; var saw_volatile = false; var saw_allowzero = false; + var saw_addrspace = false; while (true) { switch (p.token_tags[p.tok_i]) { .keyword_align => { @@ -3063,6 +3112,12 @@ const Parser = struct { p.tok_i += 1; saw_allowzero = true; }, + .keyword_addrspace => { + if (saw_addrspace) { + try p.warn(.extra_addrspace_qualifier); + } + result.addrspace_node = try p.parseAddrSpace(); + }, else => return result, } } diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig index 3fdbb3ec7b03..c64d740b01de 100644 --- a/lib/std/zig/tokenizer.zig +++ b/lib/std/zig/tokenizer.zig @@ -11,6 +11,7 @@ pub const Token = struct { }; pub const keywords = std.ComptimeStringMap(Tag, .{ + .{ "addrspace", .keyword_addrspace }, .{ "align", .keyword_align }, .{ "allowzero", .keyword_allowzero }, .{ "and", .keyword_and }, @@ -132,6 +133,7 @@ pub const Token = struct { float_literal, doc_comment, container_doc_comment, + keyword_addrspace, keyword_align, keyword_allowzero, keyword_and, @@ -251,6 +253,7 @@ pub const Token = struct { .angle_bracket_angle_bracket_right => ">>", .angle_bracket_angle_bracket_right_equal => ">>=", .tilde => "~", + .keyword_addrspace => "addrspace", .keyword_align => "align", .keyword_allowzero => "allowzero", .keyword_and => "and", diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index 93acd464f48b..bafaebfea07a 100644 --- a/src/translate_c/ast.zig +++ b/src/translate_c/ast.zig @@ -2614,6 +2614,7 @@ fn renderVar(c: *Context, node: Node) !NodeIndex { .type_node = type_node, .align_node = align_node, .section_node = section_node, + .addrspace_node = 0, }), .rhs = init_node, },