authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-10-05 14:33:27+03:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-10-05 22:26:11-04:00
log58502b8bfec51f04ad12ec65b0d52452e179256a
tree271d1a00e0f4562154d706457f08bf40ee6a1910
parentc507c7862e363c59fd61bf914f13060e19bf9f68

translate-c: respect C operator precedence in macros


2 files changed, 397 insertions(+), 166 deletions(-)

src/translate_c.zig+380-165
...@@ -5527,58 +5527,41 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {...@@ -5527,58 +5527,41 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
5527const ParseError = Error || error{ParseError};5527const ParseError = Error || error{ParseError};
55285528
5529fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {5529fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
5530 const node = try parseCPrefixOpExpr(c, m, scope);5530 // TODO parseCAssignExpr here
5531 switch (m.next().?) {5531 const node = try parseCCondExpr(c, m, scope);
5532 .QuestionMark => {5532 if (m.next().? != .Comma) {
5533 // must come immediately after expr5533 m.i -= 1;
5534 _ = try appendToken(c, .RParen, ")");5534 return node;
5535 const if_node = try transCreateNodeIf(c);5535 }
5536 if_node.condition = node;5536 _ = try appendToken(c, .Semicolon, ";");
5537 if_node.body = try parseCPrimaryExpr(c, m, scope);5537 var block_scope = try Scope.Block.init(c, scope, true);
5538 if (m.next().? != .Colon) {5538 defer block_scope.deinit();
5539 try m.fail(c, "unable to translate C expr: expected ':'", .{});
5540 return error.ParseError;
5541 }
5542 if_node.@"else" = try transCreateNodeElse(c);
5543 if_node.@"else".?.body = try parseCPrimaryExpr(c, m, scope);
5544 return &if_node.base;
5545 },
5546 .Comma => {
5547 _ = try appendToken(c, .Semicolon, ";");
5548 var block_scope = try Scope.Block.init(c, scope, true);
5549 defer block_scope.deinit();
5550
5551 var last = node;
5552 while (true) {
5553 // suppress result
5554 const lhs = try transCreateNodeIdentifier(c, "_");
5555 const op_token = try appendToken(c, .Equal, "=");
5556 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
5557 op_node.* = .{
5558 .base = .{ .tag = .Assign },
5559 .op_token = op_token,
5560 .lhs = lhs,
5561 .rhs = last,
5562 };
5563 try block_scope.statements.append(&op_node.base);
55645539
5565 last = try parseCPrefixOpExpr(c, m, scope);5540 var last = node;
5566 _ = try appendToken(c, .Semicolon, ";");5541 while (true) {
5567 if (m.next().? != .Comma) {5542 // suppress result
5568 m.i -= 1;5543 const lhs = try transCreateNodeIdentifier(c, "_");
5569 break;5544 const op_token = try appendToken(c, .Equal, "=");
5570 }5545 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
5571 }5546 op_node.* = .{
5547 .base = .{ .tag = .Assign },
5548 .op_token = op_token,
5549 .lhs = lhs,
5550 .rhs = last,
5551 };
5552 try block_scope.statements.append(&op_node.base);
55725553
5573 const break_node = try transCreateNodeBreak(c, block_scope.label, last);5554 last = try parseCCondExpr(c, m, scope);
5574 try block_scope.statements.append(&break_node.base);5555 _ = try appendToken(c, .Semicolon, ";");
5575 return try block_scope.complete(c);5556 if (m.next().? != .Comma) {
5576 },
5577 else => {
5578 m.i -= 1;5557 m.i -= 1;
5579 return node;5558 break;
5580 },5559 }
5581 }5560 }
5561
5562 const break_node = try transCreateNodeBreak(c, block_scope.label, last);
5563 try block_scope.statements.append(&break_node.base);
5564 return try block_scope.complete(c);
5582}5565}
55835566
5584fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!*ast.Node {5567fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!*ast.Node {
...@@ -5805,7 +5788,7 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {...@@ -5805,7 +5788,7 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
5805 return bytes[0..i];5788 return bytes[0..i];
5806}5789}
58075790
5808fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {5791fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
5809 const tok = m.next().?;5792 const tok = m.next().?;
5810 const slice = m.slice();5793 const slice = m.slice();
5811 switch (tok) {5794 switch (tok) {
...@@ -5952,6 +5935,30 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N...@@ -5952,6 +5935,30 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N
5952 }5935 }
5953}5936}
59545937
5938fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
5939 var node = try parseCPrimaryExprInner(c, m, scope);
5940 // In C the preprocessor would handle concatting strings while expanding macros.
5941 // This should do approximately the same by concatting any strings and identifiers
5942 // after a primary expression.
5943 while (true) {
5944 var op_token: ast.TokenIndex = undefined;
5945 var op_id: ast.Node.Tag = undefined;
5946 switch (m.peek().?) {
5947 .StringLiteral, .Identifier => {},
5948 else => break,
5949 }
5950 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
5951 op_node.* = .{
5952 .base = .{ .tag = .ArrayCat },
5953 .op_token = try appendToken(c, .PlusPlus, "++"),
5954 .lhs = node,
5955 .rhs = try parseCPrimaryExprInner(c, m, scope),
5956 };
5957 node = &op_node.base;
5958 }
5959 return node;
5960}
5961
5955fn nodeIsInfixOp(tag: ast.Node.Tag) bool {5962fn nodeIsInfixOp(tag: ast.Node.Tag) bool {
5956 return switch (tag) {5963 return switch (tag) {
5957 .Add,5964 .Add,
...@@ -6053,31 +6060,268 @@ fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node {...@@ -6053,31 +6060,268 @@ fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node {
6053 return &group_node.base;6060 return &group_node.base;
6054}6061}
60556062
6056fn parseCSuffixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {6063fn macroGroup(c: *Context, node: *ast.Node) !*ast.Node {
6057 var node = try parseCPrimaryExpr(c, m, scope);6064 if (!nodeIsInfixOp(node.tag)) return node;
6065
6066 const group_node = try c.arena.create(ast.Node.GroupedExpression);
6067 group_node.* = .{
6068 .lparen = try appendToken(c, .LParen, "("),
6069 .expr = node,
6070 .rparen = try appendToken(c, .RParen, ")"),
6071 };
6072 return &group_node.base;
6073}
6074
6075fn parseCCondExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6076 const node = try parseCOrExpr(c, m, scope);
6077 if (m.peek().? != .QuestionMark) {
6078 return node;
6079 }
6080 _ = m.next();
6081
6082 // must come immediately after expr
6083 _ = try appendToken(c, .RParen, ")");
6084 const if_node = try transCreateNodeIf(c);
6085 if_node.condition = node;
6086 if_node.body = try parseCOrExpr(c, m, scope);
6087 if (m.next().? != .Colon) {
6088 try m.fail(c, "unable to translate C expr: expected ':'", .{});
6089 return error.ParseError;
6090 }
6091 if_node.@"else" = try transCreateNodeElse(c);
6092 if_node.@"else".?.body = try parseCCondExpr(c, m, scope);
6093 return &if_node.base;
6094}
6095
6096fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6097 var node = try parseCAndExpr(c, m, scope);
6098 while (m.next().? == .PipePipe) {
6099 const lhs_node = try macroIntToBool(c, node);
6100 const op_token = try appendToken(c, .Keyword_or, "or");
6101 const rhs_node = try parseCAndExpr(c, m, scope);
6102 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6103 op_node.* = .{
6104 .base = .{ .tag = .BoolOr },
6105 .op_token = op_token,
6106 .lhs = lhs_node,
6107 .rhs = try macroIntToBool(c, rhs_node),
6108 };
6109 node = &op_node.base;
6110 }
6111 m.i -= 1;
6112 return node;
6113}
6114
6115fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6116 var node = try parseCBitOrExpr(c, m, scope);
6117 while (m.next().? == .AmpersandAmpersand) {
6118 const lhs_node = try macroIntToBool(c, node);
6119 const op_token = try appendToken(c, .Keyword_and, "and");
6120 const rhs_node = try parseCBitOrExpr(c, m, scope);
6121 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6122 op_node.* = .{
6123 .base = .{ .tag = .BoolAnd },
6124 .op_token = op_token,
6125 .lhs = lhs_node,
6126 .rhs = try macroIntToBool(c, rhs_node),
6127 };
6128 node = &op_node.base;
6129 }
6130 m.i -= 1;
6131 return node;
6132}
6133
6134fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6135 var node = try parseCBitXorExpr(c, m, scope);
6136 while (m.next().? == .Pipe) {
6137 const lhs_node = try macroBoolToInt(c, node);
6138 const op_token = try appendToken(c, .Pipe, "|");
6139 const rhs_node = try parseCBitXorExpr(c, m, scope);
6140 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6141 op_node.* = .{
6142 .base = .{ .tag = .BitOr },
6143 .op_token = op_token,
6144 .lhs = lhs_node,
6145 .rhs = try macroBoolToInt(c, rhs_node),
6146 };
6147 node = &op_node.base;
6148 }
6149 m.i -= 1;
6150 return node;
6151}
6152
6153fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6154 var node = try parseCBitAndExpr(c, m, scope);
6155 while (m.next().? == .Caret) {
6156 const lhs_node = try macroBoolToInt(c, node);
6157 const op_token = try appendToken(c, .Caret, "^");
6158 const rhs_node = try parseCBitAndExpr(c, m, scope);
6159 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6160 op_node.* = .{
6161 .base = .{ .tag = .BitXor },
6162 .op_token = op_token,
6163 .lhs = lhs_node,
6164 .rhs = try macroBoolToInt(c, rhs_node),
6165 };
6166 node = &op_node.base;
6167 }
6168 m.i -= 1;
6169 return node;
6170}
6171
6172fn parseCBitAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6173 var node = try parseCEqExpr(c, m, scope);
6174 while (m.next().? == .Ampersand) {
6175 const lhs_node = try macroBoolToInt(c, node);
6176 const op_token = try appendToken(c, .Ampersand, "&");
6177 const rhs_node = try parseCEqExpr(c, m, scope);
6178 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6179 op_node.* = .{
6180 .base = .{ .tag = .BitAnd },
6181 .op_token = op_token,
6182 .lhs = lhs_node,
6183 .rhs = try macroBoolToInt(c, rhs_node),
6184 };
6185 node = &op_node.base;
6186 }
6187 m.i -= 1;
6188 return node;
6189}
6190
6191fn parseCEqExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6192 var node = try parseCRelExpr(c, m, scope);
6058 while (true) {6193 while (true) {
6059 var op_token: ast.TokenIndex = undefined;6194 var op_token: ast.TokenIndex = undefined;
6060 var op_id: ast.Node.Tag = undefined;6195 var op_id: ast.Node.Tag = undefined;
6061 var bool_op = false;6196 switch (m.peek().?) {
6062 switch (m.next().?) {6197 .BangEqual => {
6063 .Period => {6198 op_token = try appendToken(c, .BangEqual, "!=");
6064 if (m.next().? != .Identifier) {6199 op_id = .BangEqual;
6065 try m.fail(c, "unable to translate C expr: expected identifier", .{});6200 },
6066 return error.ParseError;6201 .EqualEqual => {
6067 }6202 op_token = try appendToken(c, .EqualEqual, "==");
6203 op_id = .EqualEqual;
6204 },
6205 else => return node,
6206 }
6207 _ = m.next();
6208 const lhs_node = try macroBoolToInt(c, node);
6209 const rhs_node = try parseCRelExpr(c, m, scope);
6210 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6211 op_node.* = .{
6212 .base = .{ .tag = op_id },
6213 .op_token = op_token,
6214 .lhs = lhs_node,
6215 .rhs = try macroBoolToInt(c, rhs_node),
6216 };
6217 node = &op_node.base;
6218 }
6219}
60686220
6069 node = try transCreateNodeFieldAccess(c, node, m.slice());6221fn parseCRelExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6070 continue;6222 var node = try parseCShiftExpr(c, m, scope);
6223 while (true) {
6224 var op_token: ast.TokenIndex = undefined;
6225 var op_id: ast.Node.Tag = undefined;
6226 switch (m.peek().?) {
6227 .AngleBracketRight => {
6228 op_token = try appendToken(c, .AngleBracketRight, ">");
6229 op_id = .GreaterThan;
6071 },6230 },
6072 .Arrow => {6231 .AngleBracketRightEqual => {
6073 if (m.next().? != .Identifier) {6232 op_token = try appendToken(c, .AngleBracketRightEqual, ">=");
6074 try m.fail(c, "unable to translate C expr: expected identifier", .{});6233 op_id = .GreaterOrEqual;
6075 return error.ParseError;6234 },
6076 }6235 .AngleBracketLeft => {
6077 const deref = try transCreateNodePtrDeref(c, node);6236 op_token = try appendToken(c, .AngleBracketLeft, "<");
6078 node = try transCreateNodeFieldAccess(c, deref, m.slice());6237 op_id = .LessThan;
6079 continue;
6080 },6238 },
6239 .AngleBracketLeftEqual => {
6240 op_token = try appendToken(c, .AngleBracketLeftEqual, "<=");
6241 op_id = .LessOrEqual;
6242 },
6243 else => return node,
6244 }
6245 _ = m.next();
6246 const lhs_node = try macroBoolToInt(c, node);
6247 const rhs_node = try parseCShiftExpr(c, m, scope);
6248 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6249 op_node.* = .{
6250 .base = .{ .tag = op_id },
6251 .op_token = op_token,
6252 .lhs = lhs_node,
6253 .rhs = try macroBoolToInt(c, rhs_node),
6254 };
6255 node = &op_node.base;
6256 }
6257}
6258
6259fn parseCShiftExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6260 var node = try parseCAddSubExpr(c, m, scope);
6261 while (true) {
6262 var op_token: ast.TokenIndex = undefined;
6263 var op_id: ast.Node.Tag = undefined;
6264 switch (m.peek().?) {
6265 .AngleBracketAngleBracketLeft => {
6266 op_token = try appendToken(c, .AngleBracketAngleBracketLeft, "<<");
6267 op_id = .BitShiftLeft;
6268 },
6269 .AngleBracketAngleBracketRight => {
6270 op_token = try appendToken(c, .AngleBracketAngleBracketRight, ">>");
6271 op_id = .BitShiftRight;
6272 },
6273 else => return node,
6274 }
6275 _ = m.next();
6276 const lhs_node = try macroBoolToInt(c, node);
6277 const rhs_node = try parseCAddSubExpr(c, m, scope);
6278 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6279 op_node.* = .{
6280 .base = .{ .tag = op_id },
6281 .op_token = op_token,
6282 .lhs = lhs_node,
6283 .rhs = try macroBoolToInt(c, rhs_node),
6284 };
6285 node = &op_node.base;
6286 }
6287}
6288
6289fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6290 var node = try parseCMulExpr(c, m, scope);
6291 while (true) {
6292 var op_token: ast.TokenIndex = undefined;
6293 var op_id: ast.Node.Tag = undefined;
6294 switch (m.peek().?) {
6295 .Plus => {
6296 op_token = try appendToken(c, .Plus, "+");
6297 op_id = .Add;
6298 },
6299 .Minus => {
6300 op_token = try appendToken(c, .Minus, "-");
6301 op_id = .Sub;
6302 },
6303 else => return node,
6304 }
6305 _ = m.next();
6306 const lhs_node = try macroBoolToInt(c, node);
6307 const rhs_node = try parseCMulExpr(c, m, scope);
6308 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6309 op_node.* = .{
6310 .base = .{ .tag = op_id },
6311 .op_token = op_token,
6312 .lhs = lhs_node,
6313 .rhs = try macroBoolToInt(c, rhs_node),
6314 };
6315 node = &op_node.base;
6316 }
6317}
6318
6319fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6320 var node = try parseCUnaryExpr(c, m, scope);
6321 while (true) {
6322 var op_token: ast.TokenIndex = undefined;
6323 var op_id: ast.Node.Tag = undefined;
6324 switch (m.next().?) {
6081 .Asterisk => {6325 .Asterisk => {
6082 if (m.peek().? == .RParen) {6326 if (m.peek().? == .RParen) {
6083 // type *)6327 // type *)
...@@ -6105,59 +6349,57 @@ fn parseCSuffixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast....@@ -6105,59 +6349,57 @@ fn parseCSuffixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.
6105 op_id = .BitShiftLeft;6349 op_id = .BitShiftLeft;
6106 }6350 }
6107 },6351 },
6108 .AngleBracketAngleBracketLeft => {6352 .Slash => {
6109 op_token = try appendToken(c, .AngleBracketAngleBracketLeft, "<<");6353 op_id = .Div;
6110 op_id = .BitShiftLeft;6354 op_token = try appendToken(c, .Slash, "/");
6111 },
6112 .AngleBracketAngleBracketRight => {
6113 op_token = try appendToken(c, .AngleBracketAngleBracketRight, ">>");
6114 op_id = .BitShiftRight;
6115 },
6116 .Pipe => {
6117 op_token = try appendToken(c, .Pipe, "|");
6118 op_id = .BitOr;
6119 },
6120 .Ampersand => {
6121 op_token = try appendToken(c, .Ampersand, "&");
6122 op_id = .BitAnd;
6123 },
6124 .Plus => {
6125 op_token = try appendToken(c, .Plus, "+");
6126 op_id = .Add;
6127 },
6128 .Minus => {
6129 op_token = try appendToken(c, .Minus, "-");
6130 op_id = .Sub;
6131 },
6132 .AmpersandAmpersand => {
6133 op_token = try appendToken(c, .Keyword_and, "and");
6134 op_id = .BoolAnd;
6135 bool_op = true;
6136 },
6137 .PipePipe => {
6138 op_token = try appendToken(c, .Keyword_or, "or");
6139 op_id = .BoolOr;
6140 bool_op = true;
6141 },6355 },
6142 .AngleBracketRight => {6356 .Percent => {
6143 op_token = try appendToken(c, .AngleBracketRight, ">");6357 op_id = .Mod;
6144 op_id = .GreaterThan;6358 op_token = try appendToken(c, .Percent, "%");
6145 },6359 },
6146 .AngleBracketRightEqual => {6360 else => {
6147 op_token = try appendToken(c, .AngleBracketRightEqual, ">=");6361 m.i -= 1;
6148 op_id = .GreaterOrEqual;6362 return node;
6149 },6363 },
6150 .AngleBracketLeft => {6364 }
6151 op_token = try appendToken(c, .AngleBracketLeft, "<");6365 const lhs_node = try macroBoolToInt(c, node);
6152 op_id = .LessThan;6366 const rhs_node = try parseCUnaryExpr(c, m, scope);
6367 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6368 op_node.* = .{
6369 .base = .{ .tag = op_id },
6370 .op_token = op_token,
6371 .lhs = lhs_node,
6372 .rhs = try macroBoolToInt(c, rhs_node),
6373 };
6374 node = &op_node.base;
6375 }
6376}
6377
6378fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6379 var node = try parseCPrimaryExpr(c, m, scope);
6380 while (true) {
6381 switch (m.next().?) {
6382 .Period => {
6383 if (m.next().? != .Identifier) {
6384 try m.fail(c, "unable to translate C expr: expected identifier", .{});
6385 return error.ParseError;
6386 }
6387
6388 node = try transCreateNodeFieldAccess(c, node, m.slice());
6389 continue;
6153 },6390 },
6154 .AngleBracketLeftEqual => {6391 .Arrow => {
6155 op_token = try appendToken(c, .AngleBracketLeftEqual, "<=");6392 if (m.next().? != .Identifier) {
6156 op_id = .LessOrEqual;6393 try m.fail(c, "unable to translate C expr: expected identifier", .{});
6394 return error.ParseError;
6395 }
6396 const deref = try transCreateNodePtrDeref(c, node);
6397 node = try transCreateNodeFieldAccess(c, deref, m.slice());
6398 continue;
6157 },6399 },
6158 .LBracket => {6400 .LBracket => {
6159 const arr_node = try transCreateNodeArrayAccess(c, node);6401 const arr_node = try transCreateNodeArrayAccess(c, node);
6160 arr_node.index_expr = try parseCPrefixOpExpr(c, m, scope);6402 arr_node.index_expr = try parseCExpr(c, m, scope);
6161 arr_node.rtoken = try appendToken(c, .RBracket, "]");6403 arr_node.rtoken = try appendToken(c, .RBracket, "]");
6162 node = &arr_node.base;6404 node = &arr_node.base;
6163 if (m.next().? != .RBracket) {6405 if (m.next().? != .RBracket) {
...@@ -6171,7 +6413,7 @@ fn parseCSuffixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast....@@ -6171,7 +6413,7 @@ fn parseCSuffixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.
6171 var call_params = std.ArrayList(*ast.Node).init(c.gpa);6413 var call_params = std.ArrayList(*ast.Node).init(c.gpa);
6172 defer call_params.deinit();6414 defer call_params.deinit();
6173 while (true) {6415 while (true) {
6174 const arg = try parseCPrefixOpExpr(c, m, scope);6416 const arg = try parseCCondExpr(c, m, scope);
6175 try call_params.append(arg);6417 try call_params.append(arg);
6176 switch (m.next().?) {6418 switch (m.next().?) {
6177 .Comma => _ = try appendToken(c, .Comma, ","),6419 .Comma => _ = try appendToken(c, .Comma, ","),
...@@ -6204,7 +6446,7 @@ fn parseCSuffixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast....@@ -6204,7 +6446,7 @@ fn parseCSuffixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.
6204 defer init_vals.deinit();6446 defer init_vals.deinit();
62056447
6206 while (true) {6448 while (true) {
6207 const val = try parseCPrefixOpExpr(c, m, scope);6449 const val = try parseCCondExpr(c, m, scope);
6208 try init_vals.append(val);6450 try init_vals.append(val);
6209 switch (m.next().?) {6451 switch (m.next().?) {
6210 .Comma => _ = try appendToken(c, .Comma, ","),6452 .Comma => _ = try appendToken(c, .Comma, ","),
...@@ -6239,90 +6481,57 @@ fn parseCSuffixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast....@@ -6239,90 +6481,57 @@ fn parseCSuffixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.
6239 node = &zero_init_call.base;6481 node = &zero_init_call.base;
6240 continue;6482 continue;
6241 },6483 },
6242 .BangEqual => {6484 .PlusPlus, .MinusMinus => {
6243 op_token = try appendToken(c, .BangEqual, "!=");6485 try m.fail(c, "TODO postfix inc/dec expr", .{});
6244 op_id = .BangEqual;6486 return error.ParseError;
6245 },
6246 .EqualEqual => {
6247 op_token = try appendToken(c, .EqualEqual, "==");
6248 op_id = .EqualEqual;
6249 },
6250 .Slash => {
6251 op_id = .Div;
6252 op_token = try appendToken(c, .Slash, "/");
6253 },
6254 .Percent => {
6255 op_id = .Mod;
6256 op_token = try appendToken(c, .Percent, "%");
6257 },
6258 .StringLiteral => {
6259 op_id = .ArrayCat;
6260 op_token = try appendToken(c, .PlusPlus, "++");
6261
6262 m.i -= 1;
6263 },
6264 .Identifier => {
6265 op_id = .ArrayCat;
6266 op_token = try appendToken(c, .PlusPlus, "++");
6267
6268 m.i -= 1;
6269 },6487 },
6270 else => {6488 else => {
6271 m.i -= 1;6489 m.i -= 1;
6272 return node;6490 return node;
6273 },6491 },
6274 }6492 }
6275 const cast_fn = if (bool_op) macroIntToBool else macroBoolToInt;
6276 const lhs_node = try cast_fn(c, node);
6277 const rhs_node = try parseCPrefixOpExpr(c, m, scope);
6278 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6279 op_node.* = .{
6280 .base = .{ .tag = op_id },
6281 .op_token = op_token,
6282 .lhs = lhs_node,
6283 .rhs = try cast_fn(c, rhs_node),
6284 };
6285 node = &op_node.base;
6286 }6493 }
6287}6494}
62886495
6289fn parseCPrefixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {6496fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6290 switch (m.next().?) {6497 switch (m.next().?) {
6291 .Bang => {6498 .Bang => {
6292 const node = try transCreateNodeSimplePrefixOp(c, .BoolNot, .Bang, "!");6499 const node = try transCreateNodeSimplePrefixOp(c, .BoolNot, .Bang, "!");
6293 node.rhs = try parseCPrefixOpExpr(c, m, scope);6500 node.rhs = try macroIntToBool(c, try parseCUnaryExpr(c, m, scope));
6294 return &node.base;6501 return &node.base;
6295 },6502 },
6296 .Minus => {6503 .Minus => {
6297 const node = try transCreateNodeSimplePrefixOp(c, .Negation, .Minus, "-");6504 const node = try transCreateNodeSimplePrefixOp(c, .Negation, .Minus, "-");
6298 node.rhs = try parseCPrefixOpExpr(c, m, scope);6505 node.rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
6299 return &node.base;6506 return &node.base;
6300 },6507 },
6301 .Plus => return try parseCPrefixOpExpr(c, m, scope),6508 .Plus => return try parseCUnaryExpr(c, m, scope),
6302 .Tilde => {6509 .Tilde => {
6303 const node = try transCreateNodeSimplePrefixOp(c, .BitNot, .Tilde, "~");6510 const node = try transCreateNodeSimplePrefixOp(c, .BitNot, .Tilde, "~");
6304 node.rhs = try parseCPrefixOpExpr(c, m, scope);6511 node.rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
6305 return &node.base;6512 return &node.base;
6306 },6513 },
6307 .Asterisk => {6514 .Asterisk => {
6308 const node = try parseCPrefixOpExpr(c, m, scope);6515 const node = try macroGroup(c, try parseCUnaryExpr(c, m, scope));
6309 return try transCreateNodePtrDeref(c, node);6516 return try transCreateNodePtrDeref(c, node);
6310 },6517 },
6311 .Ampersand => {6518 .Ampersand => {
6312 const node = try transCreateNodeSimplePrefixOp(c, .AddressOf, .Ampersand, "&");6519 const node = try transCreateNodeSimplePrefixOp(c, .AddressOf, .Ampersand, "&");
6313 node.rhs = try parseCPrefixOpExpr(c, m, scope);6520 node.rhs = try macroGroup(c, try parseCUnaryExpr(c, m, scope));
6314 return &node.base;6521 return &node.base;
6315 },6522 },
6316 .Keyword_sizeof => {6523 .Keyword_sizeof => {
6317 const inner = if (m.peek().? == .LParen) blk: {6524 const inner = if (m.peek().? == .LParen) blk: {
6318 _ = m.next();6525 _ = m.next();
6319 const inner = try parseCExpr(c, m, scope);6526 // C grammar says this should be 'type-name' but we have to
6527 // use parseCMulExpr to correctly handle pointer types.
6528 const inner = try parseCMulExpr(c, m, scope);
6320 if (m.next().? != .RParen) {6529 if (m.next().? != .RParen) {
6321 try m.fail(c, "unable to translate C expr: expected ')'", .{});6530 try m.fail(c, "unable to translate C expr: expected ')'", .{});
6322 return error.ParseError;6531 return error.ParseError;
6323 }6532 }
6324 break :blk inner;6533 break :blk inner;
6325 } else try parseCPrefixOpExpr(c, m, scope);6534 } else try parseCUnaryExpr(c, m, scope);
63266535
6327 //(@import("std").meta.sizeof(dest, x))6536 //(@import("std").meta.sizeof(dest, x))
6328 const import_fn_call = try c.createBuiltinCall("@import", 1);6537 const import_fn_call = try c.createBuiltinCall("@import", 1);
...@@ -6344,7 +6553,9 @@ fn parseCPrefixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast....@@ -6344,7 +6553,9 @@ fn parseCPrefixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.
6344 try m.fail(c, "unable to translate C expr: expected '('", .{});6553 try m.fail(c, "unable to translate C expr: expected '('", .{});
6345 return error.ParseError;6554 return error.ParseError;
6346 }6555 }
6347 const inner = try parseCExpr(c, m, scope);6556 // C grammar says this should be 'type-name' but we have to
6557 // use parseCMulExpr to correctly handle pointer types.
6558 const inner = try parseCMulExpr(c, m, scope);
6348 if (m.next().? != .RParen) {6559 if (m.next().? != .RParen) {
6349 try m.fail(c, "unable to translate C expr: expected ')'", .{});6560 try m.fail(c, "unable to translate C expr: expected ')'", .{});
6350 return error.ParseError;6561 return error.ParseError;
...@@ -6355,9 +6566,13 @@ fn parseCPrefixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast....@@ -6355,9 +6566,13 @@ fn parseCPrefixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.
6355 builtin_call.rparen_token = try appendToken(c, .RParen, ")");6566 builtin_call.rparen_token = try appendToken(c, .RParen, ")");
6356 return &builtin_call.base;6567 return &builtin_call.base;
6357 },6568 },
6569 .PlusPlus, .MinusMinus => {
6570 try m.fail(c, "TODO unary inc/dec expr", .{});
6571 return error.ParseError;
6572 },
6358 else => {6573 else => {
6359 m.i -= 1;6574 m.i -= 1;
6360 return try parseCSuffixOpExpr(c, m, scope);6575 return try parseCPostfixExpr(c, m, scope);
6361 },6576 },
6362 }6577 }
6363}6578}
test/translate_c.zig+17-1
...@@ -3,6 +3,22 @@ const std = @import("std");...@@ -3,6 +3,22 @@ const std = @import("std");
3const CrossTarget = std.zig.CrossTarget;3const CrossTarget = std.zig.CrossTarget;
44
5pub fn addCases(cases: *tests.TranslateCContext) void {5pub fn addCases(cases: *tests.TranslateCContext) void {
6 cases.add("macro expressions respect C operator precedence",
7 \\#define FOO *((foo) + 2)
8 \\#define VALUE (1 + 2 * 3 + 4 * 5 + 6 << 7 | 8 == 9)
9 \\#define _AL_READ3BYTES(p) ((*(unsigned char *)(p)) \
10 \\ | (*((unsigned char *)(p) + 1) << 8) \
11 \\ | (*((unsigned char *)(p) + 2) << 16))
12 , &[_][]const u8{
13 \\pub const FOO = (foo + 2).*;
14 ,
15 \\pub const VALUE = ((((1 + (2 * 3)) + (4 * 5)) + 6) << 7) | @boolToInt(8 == 9);
16 ,
17 \\pub inline fn _AL_READ3BYTES(p: anytype) @TypeOf(((@import("std").meta.cast([*c]u8, p)).* | (((@import("std").meta.cast([*c]u8, p)) + 1).* << 8)) | (((@import("std").meta.cast([*c]u8, p)) + 2).* << 16)) {
18 \\ return ((@import("std").meta.cast([*c]u8, p)).* | (((@import("std").meta.cast([*c]u8, p)) + 1).* << 8)) | (((@import("std").meta.cast([*c]u8, p)) + 2).* << 16);
19 \\}
20 });
21
6 cases.add("extern variable in block scope",22 cases.add("extern variable in block scope",
7 \\float bar;23 \\float bar;
8 \\int foo() {24 \\int foo() {
...@@ -2978,7 +2994,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2978,7 +2994,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2978 cases.add("string concatenation in macros: three strings",2994 cases.add("string concatenation in macros: three strings",
2979 \\#define FOO "a" "b" "c"2995 \\#define FOO "a" "b" "c"
2980 , &[_][]const u8{2996 , &[_][]const u8{
2981 \\pub const FOO = "a" ++ ("b" ++ "c");2997 \\pub const FOO = "a" ++ "b" ++ "c";
2982 });2998 });
29832999
2984 cases.add("multibyte character literals",3000 cases.add("multibyte character literals",