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 {
55275527const ParseError = Error || error{ParseError};
55285528
55295529fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
5530 const node = try parseCPrefixOpExpr(c, m, scope);
5531 switch (m.next().?) {
5532 .QuestionMark => {
5533 // must come immediately after expr
5534 _ = try appendToken(c, .RParen, ")");
5535 const if_node = try transCreateNodeIf(c);
5536 if_node.condition = node;
5537 if_node.body = try parseCPrimaryExpr(c, m, scope);
5538 if (m.next().? != .Colon) {
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);
5530 // TODO parseCAssignExpr here
5531 const node = try parseCCondExpr(c, m, scope);
5532 if (m.next().? != .Comma) {
5533 m.i -= 1;
5534 return node;
5535 }
5536 _ = try appendToken(c, .Semicolon, ";");
5537 var block_scope = try Scope.Block.init(c, scope, true);
5538 defer block_scope.deinit();
55645539
5565 last = try parseCPrefixOpExpr(c, m, scope);
5566 _ = try appendToken(c, .Semicolon, ";");
5567 if (m.next().? != .Comma) {
5568 m.i -= 1;
5569 break;
5570 }
5571 }
5540 var last = node;
5541 while (true) {
5542 // suppress result
5543 const lhs = try transCreateNodeIdentifier(c, "_");
5544 const op_token = try appendToken(c, .Equal, "=");
5545 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
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);
5574 try block_scope.statements.append(&break_node.base);
5575 return try block_scope.complete(c);
5576 },
5577 else => {
5554 last = try parseCCondExpr(c, m, scope);
5555 _ = try appendToken(c, .Semicolon, ";");
5556 if (m.next().? != .Comma) {
55785557 m.i -= 1;
5579 return node;
5580 },
5558 break;
5559 }
55815560 }
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);
55825565}
55835566
55845567fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!*ast.Node {
......@@ -5805,7 +5788,7 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
58055788 return bytes[0..i];
58065789}
58075790
5808fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
5791fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
58095792 const tok = m.next().?;
58105793 const slice = m.slice();
58115794 switch (tok) {
......@@ -5952,6 +5935,30 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N
59525935 }
59535936}
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
59555962fn nodeIsInfixOp(tag: ast.Node.Tag) bool {
59565963 return switch (tag) {
59575964 .Add,
......@@ -6053,31 +6060,268 @@ fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node {
60536060 return &group_node.base;
60546061}
60556062
6056fn parseCSuffixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6057 var node = try parseCPrimaryExpr(c, m, scope);
6063fn macroGroup(c: *Context, node: *ast.Node) !*ast.Node {
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);
60586193 while (true) {
60596194 var op_token: ast.TokenIndex = undefined;
60606195 var op_id: ast.Node.Tag = undefined;
6061 var bool_op = false;
6062 switch (m.next().?) {
6063 .Period => {
6064 if (m.next().? != .Identifier) {
6065 try m.fail(c, "unable to translate C expr: expected identifier", .{});
6066 return error.ParseError;
6067 }
6196 switch (m.peek().?) {
6197 .BangEqual => {
6198 op_token = try appendToken(c, .BangEqual, "!=");
6199 op_id = .BangEqual;
6200 },
6201 .EqualEqual => {
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());
6070 continue;
6221fn parseCRelExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
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;
60716230 },
6072 .Arrow => {
6073 if (m.next().? != .Identifier) {
6074 try m.fail(c, "unable to translate C expr: expected identifier", .{});
6075 return error.ParseError;
6076 }
6077 const deref = try transCreateNodePtrDeref(c, node);
6078 node = try transCreateNodeFieldAccess(c, deref, m.slice());
6079 continue;
6231 .AngleBracketRightEqual => {
6232 op_token = try appendToken(c, .AngleBracketRightEqual, ">=");
6233 op_id = .GreaterOrEqual;
6234 },
6235 .AngleBracketLeft => {
6236 op_token = try appendToken(c, .AngleBracketLeft, "<");
6237 op_id = .LessThan;
60806238 },
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().?) {
60816325 .Asterisk => {
60826326 if (m.peek().? == .RParen) {
60836327 // type *)
......@@ -6105,59 +6349,57 @@ fn parseCSuffixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.
61056349 op_id = .BitShiftLeft;
61066350 }
61076351 },
6108 .AngleBracketAngleBracketLeft => {
6109 op_token = try appendToken(c, .AngleBracketAngleBracketLeft, "<<");
6110 op_id = .BitShiftLeft;
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;
6352 .Slash => {
6353 op_id = .Div;
6354 op_token = try appendToken(c, .Slash, "/");
61416355 },
6142 .AngleBracketRight => {
6143 op_token = try appendToken(c, .AngleBracketRight, ">");
6144 op_id = .GreaterThan;
6356 .Percent => {
6357 op_id = .Mod;
6358 op_token = try appendToken(c, .Percent, "%");
61456359 },
6146 .AngleBracketRightEqual => {
6147 op_token = try appendToken(c, .AngleBracketRightEqual, ">=");
6148 op_id = .GreaterOrEqual;
6360 else => {
6361 m.i -= 1;
6362 return node;
61496363 },
6150 .AngleBracketLeft => {
6151 op_token = try appendToken(c, .AngleBracketLeft, "<");
6152 op_id = .LessThan;
6364 }
6365 const lhs_node = try macroBoolToInt(c, node);
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;
61536390 },
6154 .AngleBracketLeftEqual => {
6155 op_token = try appendToken(c, .AngleBracketLeftEqual, "<=");
6156 op_id = .LessOrEqual;
6391 .Arrow => {
6392 if (m.next().? != .Identifier) {
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;
61576399 },
61586400 .LBracket => {
61596401 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);
61616403 arr_node.rtoken = try appendToken(c, .RBracket, "]");
61626404 node = &arr_node.base;
61636405 if (m.next().? != .RBracket) {
......@@ -6171,7 +6413,7 @@ fn parseCSuffixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.
61716413 var call_params = std.ArrayList(*ast.Node).init(c.gpa);
61726414 defer call_params.deinit();
61736415 while (true) {
6174 const arg = try parseCPrefixOpExpr(c, m, scope);
6416 const arg = try parseCCondExpr(c, m, scope);
61756417 try call_params.append(arg);
61766418 switch (m.next().?) {
61776419 .Comma => _ = try appendToken(c, .Comma, ","),
......@@ -6204,7 +6446,7 @@ fn parseCSuffixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.
62046446 defer init_vals.deinit();
62056447
62066448 while (true) {
6207 const val = try parseCPrefixOpExpr(c, m, scope);
6449 const val = try parseCCondExpr(c, m, scope);
62086450 try init_vals.append(val);
62096451 switch (m.next().?) {
62106452 .Comma => _ = try appendToken(c, .Comma, ","),
......@@ -6239,90 +6481,57 @@ fn parseCSuffixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.
62396481 node = &zero_init_call.base;
62406482 continue;
62416483 },
6242 .BangEqual => {
6243 op_token = try appendToken(c, .BangEqual, "!=");
6244 op_id = .BangEqual;
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;
6484 .PlusPlus, .MinusMinus => {
6485 try m.fail(c, "TODO postfix inc/dec expr", .{});
6486 return error.ParseError;
62696487 },
62706488 else => {
62716489 m.i -= 1;
62726490 return node;
62736491 },
62746492 }
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;
62866493 }
62876494}
62886495
6289fn parseCPrefixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6496fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
62906497 switch (m.next().?) {
62916498 .Bang => {
62926499 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));
62946501 return &node.base;
62956502 },
62966503 .Minus => {
62976504 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));
62996506 return &node.base;
63006507 },
6301 .Plus => return try parseCPrefixOpExpr(c, m, scope),
6508 .Plus => return try parseCUnaryExpr(c, m, scope),
63026509 .Tilde => {
63036510 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));
63056512 return &node.base;
63066513 },
63076514 .Asterisk => {
6308 const node = try parseCPrefixOpExpr(c, m, scope);
6515 const node = try macroGroup(c, try parseCUnaryExpr(c, m, scope));
63096516 return try transCreateNodePtrDeref(c, node);
63106517 },
63116518 .Ampersand => {
63126519 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));
63146521 return &node.base;
63156522 },
63166523 .Keyword_sizeof => {
63176524 const inner = if (m.peek().? == .LParen) blk: {
63186525 _ = 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);
63206529 if (m.next().? != .RParen) {
63216530 try m.fail(c, "unable to translate C expr: expected ')'", .{});
63226531 return error.ParseError;
63236532 }
63246533 break :blk inner;
6325 } else try parseCPrefixOpExpr(c, m, scope);
6534 } else try parseCUnaryExpr(c, m, scope);
63266535
63276536 //(@import("std").meta.sizeof(dest, x))
63286537 const import_fn_call = try c.createBuiltinCall("@import", 1);
......@@ -6344,7 +6553,9 @@ fn parseCPrefixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.
63446553 try m.fail(c, "unable to translate C expr: expected '('", .{});
63456554 return error.ParseError;
63466555 }
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);
63486559 if (m.next().? != .RParen) {
63496560 try m.fail(c, "unable to translate C expr: expected ')'", .{});
63506561 return error.ParseError;
......@@ -6355,9 +6566,13 @@ fn parseCPrefixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.
63556566 builtin_call.rparen_token = try appendToken(c, .RParen, ")");
63566567 return &builtin_call.base;
63576568 },
6569 .PlusPlus, .MinusMinus => {
6570 try m.fail(c, "TODO unary inc/dec expr", .{});
6571 return error.ParseError;
6572 },
63586573 else => {
63596574 m.i -= 1;
6360 return try parseCSuffixOpExpr(c, m, scope);
6575 return try parseCPostfixExpr(c, m, scope);
63616576 },
63626577 }
63636578}
test/translate_c.zig+17-1
......@@ -3,6 +3,22 @@ const std = @import("std");
33const CrossTarget = std.zig.CrossTarget;
44
55pub 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
622 cases.add("extern variable in block scope",
723 \\float bar;
824 \\int foo() {
......@@ -2978,7 +2994,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
29782994 cases.add("string concatenation in macros: three strings",
29792995 \\#define FOO "a" "b" "c"
29802996 , &[_][]const u8{
2981 \\pub const FOO = "a" ++ ("b" ++ "c");
2997 \\pub const FOO = "a" ++ "b" ++ "c";
29822998 });
29832999
29843000 cases.add("multibyte character literals",