authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2019-12-15 14:44:11+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2019-12-15 14:44:11+02:00
log75218d4765bdf0dbdf97581b7dd05b45570ab940
tree38782cf017e2d9fd3a3e6e8af802213a31f943db
parentc3724a6e723dfb5ec78c6ca87e2f02e121d39bc2
signature Commit is signed but in an unrecognized format.

translate-c-2 macros


4 files changed, 542 insertions(+), 81 deletions(-)

src-self-hosted/c_tokenizer.zig+157-57
......@@ -1,4 +1,5 @@
11const std = @import("std");
2const expect = std.testing.expect;
23
34pub const TokenList = std.SegmentedList(CToken, 32);
45
......@@ -28,6 +29,7 @@ pub const CToken = struct {
2829
2930 pub const NumLitSuffix = enum {
3031 None,
32 F,
3133 L,
3234 U,
3335 LU,
......@@ -39,19 +41,18 @@ pub const CToken = struct {
3941pub fn tokenizeCMacro(tl: *TokenList, chars: [*]const u8) !void {
4042 var index: usize = 0;
4143 while (true) {
42 const tok = try next(chars[index..], &index);
43 tl.push(tok);
44 const tok = try next(chars, &index);
45 try tl.push(tok);
4446 if (tok.id == .Eof)
4547 return;
4648 }
4749}
4850
49fn next(chars: [*]const u8, index: *usize) !CToken {
51fn next(chars: [*]const u8, i: *usize) !CToken {
5052 var state: enum {
5153 Start,
5254 GotLt,
53 ExpectChar,
54 ExpectEndQuot,
55 CharLit,
5556 OpenComment,
5657 Comment,
5758 CommentStar,
......@@ -62,6 +63,7 @@ fn next(chars: [*]const u8, index: *usize) !CToken {
6263 Octal,
6364 GotZero,
6465 Hex,
66 Bin,
6567 Float,
6668 ExpSign,
6769 FloatExp,
......@@ -70,7 +72,6 @@ fn next(chars: [*]const u8, index: *usize) !CToken {
7072 NumLitIntSuffixL,
7173 NumLitIntSuffixLL,
7274 NumLitIntSuffixUL,
73 GotLt,
7475 } = .Start;
7576
7677 var result = CToken{
......@@ -79,9 +80,10 @@ fn next(chars: [*]const u8, index: *usize) !CToken {
7980 };
8081 var begin_index: usize = 0;
8182 var digits: u8 = 0;
82 var pre_escape = .Start;
83 var pre_escape = state;
8384
84 for (chars[begin_index..]) |c, i| {
85 while (true) {
86 const c = chars[i.*];
8587 if (c == 0) {
8688 switch (state) {
8789 .Start => {
......@@ -90,22 +92,25 @@ fn next(chars: [*]const u8, index: *usize) !CToken {
9092 .Identifier,
9193 .Decimal,
9294 .Hex,
95 .Bin,
9396 .Octal,
9497 .GotZero,
98 .Float,
99 .FloatExp,
100 => {
101 result.bytes = chars[begin_index..i.*];
102 return result;
103 },
95104 .NumLitIntSuffixU,
96105 .NumLitIntSuffixL,
97106 .NumLitIntSuffixUL,
98107 .NumLitIntSuffixLL,
99 .Float,
100 .FloatExp,
101108 .GotLt,
102109 => {
103110 return result;
104111 },
105 .ExpectChar,
106 .ExpectEndQuot,
112 .CharLit,
107113 .OpenComment,
108 .LineComment,
109114 .Comment,
110115 .CommentStar,
111116 .Backslash,
......@@ -115,20 +120,20 @@ fn next(chars: [*]const u8, index: *usize) !CToken {
115120 => return error.TokenizingFailed,
116121 }
117122 }
118 index.* += 1;
123 i.* += 1;
119124 switch (state) {
120125 .Start => {
121126 switch (c) {
122127 ' ', '\t', '\x0B', '\x0C' => {},
123128 '\'' => {
124 state = .ExpectChar;
129 state = .CharLit;
125130 result.id = .CharLit;
126 begin_index = i;
131 begin_index = i.* - 1;
127132 },
128133 '\"' => {
129134 state = .String;
130135 result.id = .StrLit;
131 begin_index = i;
136 begin_index = i.* - 1;
132137 },
133138 '/' => {
134139 state = .OpenComment;
......@@ -142,17 +147,17 @@ fn next(chars: [*]const u8, index: *usize) !CToken {
142147 'a'...'z', 'A'...'Z', '_' => {
143148 state = .Identifier;
144149 result.id = .Identifier;
145 begin_index = i;
150 begin_index = i.* - 1;
146151 },
147152 '1'...'9' => {
148153 state = .Decimal;
149154 result.id = .NumLitInt;
150 begin_index = i;
155 begin_index = i.* - 1;
151156 },
152157 '0' => {
153158 state = .GotZero;
154159 result.id = .NumLitInt;
155 begin_index = i;
160 begin_index = i.* - 1;
156161 },
157162 '.' => {
158163 result.id = .Dot;
......@@ -206,12 +211,23 @@ fn next(chars: [*]const u8, index: *usize) !CToken {
206211 'e', 'E' => {
207212 state = .ExpSign;
208213 },
209 'f', 'F', 'l', 'L' => {
210 result.bytes = chars[begin_index..i];
214 'f',
215 'F',
216 => {
217 i.* -= 1;
218 result.num_lit_suffix = .F;
219 result.bytes = chars[begin_index..i.*];
220 return result;
221 },
222 'l', 'L' => {
223 i.* -= 1;
224 result.num_lit_suffix = .L;
225 result.bytes = chars[begin_index..i.*];
211226 return result;
212227 },
213228 else => {
214 result.bytes = chars[begin_index..i];
229 i.* -= 1;
230 result.bytes = chars[begin_index..i.*];
215231 return result;
216232 },
217233 }
......@@ -238,12 +254,19 @@ fn next(chars: [*]const u8, index: *usize) !CToken {
238254 .FloatExp => {
239255 switch (c) {
240256 '0'...'9' => {},
241 'f', 'F', 'l', 'L' => {
242 result.bytes = chars[begin_index..i];
257 'f', 'F' => {
258 result.num_lit_suffix = .F;
259 result.bytes = chars[begin_index .. i.* - 1];
260 return result;
261 },
262 'l', 'L' => {
263 result.num_lit_suffix = .L;
264 result.bytes = chars[begin_index .. i.* - 1];
243265 return result;
244266 },
245267 else => {
246 result.bytes = chars[begin_index..i];
268 i.* -= 1;
269 result.bytes = chars[begin_index..i.*];
247270 return result;
248271 },
249272 }
......@@ -255,17 +278,20 @@ fn next(chars: [*]const u8, index: *usize) !CToken {
255278 'u', 'U' => {
256279 state = .NumLitIntSuffixU;
257280 result.num_lit_suffix = .U;
281 result.bytes = chars[begin_index .. i.* - 1];
258282 },
259283 'l', 'L' => {
260284 state = .NumLitIntSuffixL;
261285 result.num_lit_suffix = .L;
286 result.bytes = chars[begin_index .. i.* - 1];
262287 },
263288 '.' => {
264289 result.id = .NumLitFloat;
265290 state = .Float;
266291 },
267292 else => {
268 result.bytes = chars[begin_index..i];
293 i.* -= 1;
294 result.bytes = chars[begin_index..i.*];
269295 return result;
270296 },
271297 }
......@@ -275,15 +301,25 @@ fn next(chars: [*]const u8, index: *usize) !CToken {
275301 'x', 'X' => {
276302 state = .Hex;
277303 },
304 'b', 'B' => {
305 state = .Bin;
306 },
278307 '.' => {
279308 state = .Float;
280309 result.id = .NumLitFloat;
281310 },
282 'l', 'L', 'u', 'U' => {
283 c -= 1;
284 state = .Decimal;
311 'u', 'U' => {
312 state = .NumLitIntSuffixU;
313 result.num_lit_suffix = .U;
314 result.bytes = chars[begin_index .. i.* - 1];
315 },
316 'l', 'L' => {
317 state = .NumLitIntSuffixL;
318 result.num_lit_suffix = .L;
319 result.bytes = chars[begin_index .. i.* - 1];
285320 },
286321 else => {
322 i.* -= 1;
287323 state = .Octal;
288324 },
289325 }
......@@ -293,7 +329,8 @@ fn next(chars: [*]const u8, index: *usize) !CToken {
293329 '0'...'7' => {},
294330 '8', '9' => return error.TokenizingFailed,
295331 else => {
296 result.bytes = chars[begin_index..i];
332 i.* -= 1;
333 result.bytes = chars[begin_index..i.*];
297334 return result;
298335 },
299336 }
......@@ -301,23 +338,44 @@ fn next(chars: [*]const u8, index: *usize) !CToken {
301338 .Hex => {
302339 switch (c) {
303340 '0'...'9', 'a'...'f', 'A'...'F' => {},
304
305 'p', 'P' => {
306 result.id = .NumLitFloat;
307 state = .ExpSign;
341 'u', 'U' => {
342 // marks the number literal as unsigned
343 state = .NumLitIntSuffixU;
344 result.num_lit_suffix = .U;
345 result.bytes = chars[begin_index .. i.* - 1];
308346 },
347 'l', 'L' => {
348 // marks the number literal as long
349 state = .NumLitIntSuffixL;
350 result.num_lit_suffix = .L;
351 result.bytes = chars[begin_index .. i.* - 1];
352 },
353 else => {
354 i.* -= 1;
355 result.bytes = chars[begin_index..i.*];
356 return result;
357 },
358 }
359 },
360 .Bin => {
361 switch (c) {
362 '0'...'1' => {},
363 '2'...'9' => return error.TokenizingFailed,
309364 'u', 'U' => {
310365 // marks the number literal as unsigned
311366 state = .NumLitIntSuffixU;
312367 result.num_lit_suffix = .U;
368 result.bytes = chars[begin_index .. i.* - 1];
313369 },
314370 'l', 'L' => {
315371 // marks the number literal as long
316372 state = .NumLitIntSuffixL;
317373 result.num_lit_suffix = .L;
374 result.bytes = chars[begin_index .. i.* - 1];
318375 },
319376 else => {
320 result.bytes = chars[begin_index..i];
377 i.* -= 1;
378 result.bytes = chars[begin_index..i.*];
321379 return result;
322380 },
323381 }
......@@ -329,7 +387,7 @@ fn next(chars: [*]const u8, index: *usize) !CToken {
329387 state = .NumLitIntSuffixUL;
330388 },
331389 else => {
332 result.bytes = chars[begin_index..i - 1];
390 i.* -= 1;
333391 return result;
334392 },
335393 }
......@@ -342,11 +400,10 @@ fn next(chars: [*]const u8, index: *usize) !CToken {
342400 },
343401 'u', 'U' => {
344402 result.num_lit_suffix = .LU;
345 result.bytes = chars[begin_index..i - 2];
346403 return result;
347404 },
348405 else => {
349 result.bytes = chars[begin_index..i - 1];
406 i.* -= 1;
350407 return result;
351408 },
352409 }
......@@ -355,11 +412,10 @@ fn next(chars: [*]const u8, index: *usize) !CToken {
355412 switch (c) {
356413 'u', 'U' => {
357414 result.num_lit_suffix = .LLU;
358 result.bytes = chars[begin_index..i - 3];
359415 return result;
360416 },
361417 else => {
362 result.bytes = chars[begin_index..i - 2];
418 i.* -= 1;
363419 return result;
364420 },
365421 }
......@@ -368,11 +424,10 @@ fn next(chars: [*]const u8, index: *usize) !CToken {
368424 switch (c) {
369425 'l', 'L' => {
370426 result.num_lit_suffix = .LLU;
371 result.bytes = chars[begin_index..i - 3];
372427 return result;
373428 },
374429 else => {
375 result.bytes = chars[begin_index..i - 2];
430 i.* -= 1;
376431 return result;
377432 },
378433 }
......@@ -381,35 +436,28 @@ fn next(chars: [*]const u8, index: *usize) !CToken {
381436 switch (c) {
382437 '_', 'a'...'z', 'A'...'Z', '0'...'9' => {},
383438 else => {
384 result.bytes = chars[begin_index..i];
439 i.* -= 1;
440 result.bytes = chars[begin_index..i.*];
385441 return result;
386442 },
387443 }
388444 },
389 .String => {
445 .String => { // TODO char escapes
390446 switch (c) {
391447 '\"' => {
392 result.bytes = chars[begin_index + 1 .. i];
448 result.bytes = chars[begin_index + 1 .. i.* - 1];
393449 return result;
394450 },
395451 else => {},
396452 }
397453 },
398 .ExpectChar => {
399 switch (c) {
400 '\'' => return error.TokenizingFailed,
401 else => {
402 state = .ExpectEndQuot;
403 },
404 }
405 },
406 .ExpectEndQuot => {
454 .CharLit => {
407455 switch (c) {
408456 '\'' => {
409 result.bytes = chars[begin_index + 1 .. i];
457 result.bytes = chars[begin_index + 1 .. i.* - 1];
410458 return result;
411459 },
412 else => return error.TokenizingFailed,
460 else => {},
413461 }
414462 },
415463 .OpenComment => {
......@@ -455,4 +503,56 @@ fn next(chars: [*]const u8, index: *usize) !CToken {
455503 },
456504 }
457505 }
506 unreachable;
507}
508
509test "tokenize macro" {
510 var tl = TokenList.init(std.heap.page_allocator);
511 defer tl.deinit();
512
513 const src = "TEST 0\n";
514 try tokenizeCMacro(&tl, src);
515 var it = tl.iterator(0);
516 expect(it.next().?.id == .Identifier);
517 expect(std.mem.eql(u8, it.next().?.bytes, "0"));
518 expect(it.next().?.id == .Eof);
519 expect(it.next() == null);
520 tl.shrink(0);
521
522 const src2 = "__FLT_MIN_10_EXP__ -37\n";
523 try tokenizeCMacro(&tl, src2);
524 it = tl.iterator(0);
525 expect(std.mem.eql(u8, it.next().?.bytes, "__FLT_MIN_10_EXP__"));
526 expect(it.next().?.id == .Minus);
527 expect(std.mem.eql(u8, it.next().?.bytes, "37"));
528 expect(it.next().?.id == .Eof);
529 expect(it.next() == null);
530 tl.shrink(0);
531
532 const src3 = "__llvm__ 1\n#define";
533 try tokenizeCMacro(&tl, src3);
534 it = tl.iterator(0);
535 expect(std.mem.eql(u8, it.next().?.bytes, "__llvm__"));
536 expect(std.mem.eql(u8, it.next().?.bytes, "1"));
537 expect(it.next().?.id == .Eof);
538 expect(it.next() == null);
539 tl.shrink(0);
540
541 const src4 = "TEST 2";
542 try tokenizeCMacro(&tl, src4);
543 it = tl.iterator(0);
544 expect(it.next().?.id == .Identifier);
545 expect(std.mem.eql(u8, it.next().?.bytes, "2"));
546 expect(it.next().?.id == .Eof);
547 expect(it.next() == null);
548 tl.shrink(0);
549
550 const src5 = "FOO 0l";
551 try tokenizeCMacro(&tl, src5);
552 it = tl.iterator(0);
553 expect(it.next().?.id == .Identifier);
554 expect(std.mem.eql(u8, it.next().?.bytes, "0"));
555 expect(it.next().?.id == .Eof);
556 expect(it.next() == null);
557 tl.shrink(0);
458558}
src-self-hosted/clang.zig+22
......@@ -75,6 +75,7 @@ pub const struct_ZigClangWhileStmt = @OpaqueType();
7575pub const struct_ZigClangFunctionType = @OpaqueType();
7676pub const struct_ZigClangPredefinedExpr = @OpaqueType();
7777pub const struct_ZigClangInitListExpr = @OpaqueType();
78pub const ZigClangPreprocessingRecord = @OpaqueType();
7879
7980pub const ZigClangBO = extern enum {
8081 PtrMemD,
......@@ -717,6 +718,18 @@ pub const ZigClangEnumDecl_enumerator_iterator = extern struct {
717718 opaque: *c_void,
718719};
719720
721pub const ZigClangPreprocessingRecord_iterator = extern struct {
722 I: c_int,
723 Self: *ZigClangPreprocessingRecord,
724};
725
726pub const ZigClangPreprocessedEntity_EntityKind = extern enum {
727 InvalidKind,
728 MacroExpansionKind,
729 MacroDefinitionKind,
730 InclusionDirectiveKind,
731};
732
720733pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation;
721734pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8;
722735pub extern fn ZigClangSourceManager_getSpellingLineNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint;
......@@ -1014,3 +1027,12 @@ pub extern fn ZigClangFieldDecl_getLocation(*const struct_ZigClangFieldDecl) str
10141027
10151028pub extern fn ZigClangEnumConstantDecl_getInitExpr(*const ZigClangEnumConstantDecl) ?*const ZigClangExpr;
10161029pub extern fn ZigClangEnumConstantDecl_getInitVal(*const ZigClangEnumConstantDecl) *const ZigClangAPSInt;
1030
1031pub extern fn ZigClangASTUnit_getLocalPreprocessingEntities_begin(*ZigClangASTUnit) ZigClangPreprocessingRecord_iterator;
1032pub extern fn ZigClangASTUnit_getLocalPreprocessingEntities_end(*ZigClangASTUnit) ZigClangPreprocessingRecord_iterator;
1033pub extern fn ZigClangPreprocessingRecord_iterator_deref(ZigClangPreprocessingRecord_iterator) *ZigClangPreprocessedEntity;
1034pub extern fn ZigClangPreprocessedEntity_getKind(*const ZigClangPreprocessedEntity) ZigClangPreprocessedEntity_EntityKind;
1035
1036pub extern fn ZigClangMacroDefinitionRecord_getName_getNameStart(*const ZigClangMacroDefinitionRecord) [*:0]const u8;
1037pub extern fn ZigClangMacroDefinitionRecord_getSourceRange_getBegin(*const ZigClangMacroDefinitionRecord) ZigClangSourceLocation;
1038pub extern fn ZigClangMacroDefinitionRecord_getSourceRange_getEnd(*const ZigClangMacroDefinitionRecord) ZigClangSourceLocation;
src-self-hosted/translate_c.zig+294-11
......@@ -6,6 +6,8 @@ const assert = std.debug.assert;
66const ast = std.zig.ast;
77const Token = std.zig.Token;
88usingnamespace @import("clang.zig");
9const ctok = @import("c_tokenizer.zig");
10const CToken = ctok.CToken;
911
1012const CallingConvention = std.builtin.TypeInfo.CallingConvention;
1113
......@@ -31,6 +33,7 @@ fn addrEql(a: usize, b: usize) bool {
3133 return a == b;
3234}
3335
36const MacroTable = std.StringHashMap(*ast.Node);
3437const SymbolTable = std.StringHashMap(void);
3538const AliasList = std.SegmentedList(struct {
3639 alias: []const u8,
......@@ -106,6 +109,7 @@ const Context = struct {
106109 decl_table: DeclTable,
107110 alias_list: AliasList,
108111 sym_table: SymbolTable,
112 macro_table: MacroTable,
109113 global_scope: *Scope.Root,
110114 ptr_params: std.BufSet,
111115 clang_context: *ZigClangASTContext,
......@@ -193,6 +197,7 @@ pub fn translate(
193197 .decl_table = DeclTable.init(arena),
194198 .alias_list = AliasList.init(arena),
195199 .sym_table = SymbolTable.init(arena),
200 .macro_table = MacroTable.init(arena),
196201 .global_scope = try arena.create(Scope.Root),
197202 .ptr_params = std.BufSet.init(arena),
198203 .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?,
......@@ -207,6 +212,14 @@ pub fn translate(
207212 if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) {
208213 return context.err;
209214 }
215
216 try transPreprocessorEntities(&context, ast_unit);
217
218 var macro_it = context.macro_table.iterator();
219 while (macro_it.next()) |kv| {
220 try addTopLevelDecl(&context, kv.key, kv.value);
221 }
222
210223 var it = context.alias_list.iterator(0);
211224 while (it.next()) |alias| {
212225 if (!context.sym_table.contains(alias.alias)) {
......@@ -1931,18 +1944,18 @@ fn transCreateNodeInt(c: *Context, int: var) !*ast.Node {
19311944 return &node.base;
19321945}
19331946
1934fn transCreateNodeOpaqueType(c: *Context) !*ast.Node {
1935 const builtin_tok = try appendToken(c, .Builtin, "@OpaqueType");
1936 _ = try appendToken(c, .LParen, "(");
1937 const rparen_tok = try appendToken(c, .RParen, ")");
1938
1939 const call_node = try c.a().create(ast.Node.BuiltinCall);
1940 call_node.* = ast.Node.BuiltinCall{
1941 .base = ast.Node{ .id = ast.Node.Id.BuiltinCall },
1942 .builtin_token = builtin_tok,
1943 .params = ast.Node.BuiltinCall.ParamList.init(c.a()),
1944 .rparen_token = rparen_tok,
1947fn transCreateNodeFloat(c: *Context, int: var) !*ast.Node {
1948 const token = try appendTokenFmt(c, .FloatLiteral, "{}", .{int});
1949 const node = try c.a().create(ast.Node.FloatLiteral);
1950 node.* = .{
1951 .token = token,
19451952 };
1953 return &node.base;
1954}
1955
1956fn transCreateNodeOpaqueType(c: *Context) !*ast.Node {
1957 const call_node = try transCreateNodeBuiltinFnCall(c, "@OpaqueType");
1958 call_node.rparen_token = try appendToken(c, .RParen, ")");
19461959 return &call_node.base;
19471960}
19481961
......@@ -2441,3 +2454,273 @@ fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {
24412454pub fn freeErrors(errors: []ClangErrMsg) void {
24422455 ZigClangErrorMsg_delete(errors.ptr, errors.len);
24432456}
2457
2458fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
2459 // TODO if we see #undef, delete it from the table
2460 var it = ZigClangASTUnit_getLocalPreprocessingEntities_begin(unit);
2461 const it_end = ZigClangASTUnit_getLocalPreprocessingEntities_end(unit);
2462 var tok_list = ctok.TokenList.init(c.a());
2463
2464 while (it.I != it_end.I) : (it.I += 1) {
2465 const entity = ZigClangPreprocessingRecord_iterator_deref(it);
2466 tok_list.shrink(0);
2467
2468 switch (ZigClangPreprocessedEntity_getKind(entity)) {
2469 .MacroExpansionKind => {
2470 // TODO
2471 },
2472 .MacroDefinitionKind => {
2473 const macro = @ptrCast(*ZigClangMacroDefinitionRecord, entity);
2474 const raw_name = ZigClangMacroDefinitionRecord_getName_getNameStart(macro);
2475 const begin_loc = ZigClangMacroDefinitionRecord_getSourceRange_getBegin(macro);
2476
2477 const name = try c.str(raw_name);
2478 // if (name_exists_global(c, name)) { // TODO
2479 // continue;
2480 // }
2481
2482 const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc);
2483 try transMacroDefine(c, &tok_list, name, begin_c, begin_loc);
2484 },
2485 else => {},
2486 }
2487 }
2488}
2489
2490fn transMacroDefine(c: *Context, tok_list: *ctok.TokenList, name: []const u8, char_ptr: [*]const u8, source_loc: ZigClangSourceLocation) Error!void {
2491 ctok.tokenizeCMacro(tok_list, char_ptr) catch |err| switch (err) {
2492 error.OutOfMemory => |e| return e,
2493 else => return failDecl(c, source_loc, name, "unable to tokenize macro definition", .{}),
2494 };
2495 const rp = makeRestorePoint(c);
2496
2497 var it = tok_list.iterator(0);
2498 const first_tok = it.next().?;
2499 assert(first_tok.id == .Identifier and std.mem.eql(u8, first_tok.bytes, name));
2500 const next = it.peek().?;
2501 switch (next.id) {
2502 .Identifier => {
2503 // if it equals itself, ignore. for example, from stdio.h:
2504 // #define stdin stdin
2505 if (std.mem.eql(u8, name, next.bytes)) {
2506 return;
2507 }
2508 },
2509 .Eof => {
2510 // this means it is a macro without a value
2511 // we don't care about such things
2512 return;
2513 },
2514 else => {},
2515 }
2516
2517 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
2518 const mut_tok = try appendToken(c, .Keyword_const, "const");
2519 const name_tok = try appendIdentifier(c, name);
2520
2521 const eq_tok = try appendToken(c, .Equal, "=");
2522
2523 const init_node = parseCExpr(rp, &it, source_loc) catch |err| switch (err) {
2524 error.UnsupportedTranslation,
2525 error.ParseError,
2526 => return failDecl(c, source_loc, name, "unable to translate macro", .{}),
2527 error.OutOfMemory => |e| return e,
2528 };
2529
2530 const node = try c.a().create(ast.Node.VarDecl);
2531 node.* = ast.Node.VarDecl{
2532 .doc_comments = null,
2533 .visib_token = visib_tok,
2534 .thread_local_token = null,
2535 .name_token = name_tok,
2536 .eq_token = eq_tok,
2537 .mut_token = mut_tok,
2538 .comptime_token = null,
2539 .extern_export_token = null,
2540 .lib_name = null,
2541 .type_node = null,
2542 .align_node = null,
2543 .section_node = null,
2544 .init_node = init_node,
2545 .semicolon_token = try appendToken(c, .Semicolon, ";"),
2546 };
2547 _ = try c.macro_table.put(name, &node.base);
2548}
2549
2550const ParseError = Error || error{
2551 ParseError,
2552 UnsupportedTranslation,
2553};
2554
2555fn parseCExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation) ParseError!*ast.Node {
2556 return parseCPrefixOpExpr(rp, it, source_loc);
2557}
2558
2559fn parseCNumLit(rp: RestorePoint, tok: *CToken, source_loc: ZigClangSourceLocation) ParseError!*ast.Node {
2560 if (tok.id == .NumLitInt) {
2561 if (tok.num_lit_suffix == .None) {
2562 if (tok.bytes.len > 2 and tok.bytes[0] == '0') {
2563 switch (tok.bytes[1]) {
2564 '0'...'7' => {
2565 // octal
2566 return transCreateNodeInt(rp.c, try std.fmt.allocPrint(rp.c.a(), "0o{}", .{tok.bytes}));
2567 },
2568 else => {},
2569 }
2570 }
2571 return transCreateNodeInt(rp.c, tok.bytes);
2572 }
2573 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
2574 try cast_node.params.push(try transCreateNodeIdentifier(rp.c, switch (tok.num_lit_suffix) {
2575 .U => "c_uint",
2576 .L => "c_long",
2577 .LU => "c_ulong",
2578 .LL => "c_longlong",
2579 .LLU => "c_ulonglong",
2580 else => unreachable,
2581 }));
2582 _ = try appendToken(rp.c, .Comma, ",");
2583 try cast_node.params.push(try transCreateNodeInt(rp.c, tok.bytes));
2584 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2585 return &cast_node.base;
2586 } else if (tok.id == .NumLitFloat) {
2587 if (tok.num_lit_suffix == .None) {
2588 return transCreateNodeFloat(rp.c, tok.bytes);
2589 }
2590 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
2591 try cast_node.params.push(try transCreateNodeIdentifier(rp.c, switch (tok.num_lit_suffix) {
2592 .F => "f32",
2593 .L => "f64",
2594 else => unreachable,
2595 }));
2596 _ = try appendToken(rp.c, .Comma, ",");
2597 try cast_node.params.push(try transCreateNodeFloat(rp.c, tok.bytes));
2598 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2599 return &cast_node.base;
2600 } else
2601 return revertAndWarn(
2602 rp,
2603 error.ParseError,
2604 source_loc,
2605 "expected number literal",
2606 .{},
2607 );
2608}
2609
2610fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation) ParseError!*ast.Node {
2611 const tok = it.next().?;
2612 switch (tok.id) {
2613 .CharLit => {
2614 const buf = try rp.c.a().alloc(u8, tok.bytes.len + "''".len);
2615 buf[0] = '\'';
2616 writeEscapedString(buf[1..], tok.bytes);
2617 buf[buf.len - 1] = '\'';
2618 const token = try appendToken(rp.c, .CharLiteral, buf);
2619 const node = try rp.c.a().create(ast.Node.CharLiteral);
2620 node.* = ast.Node.CharLiteral{
2621 .token = token,
2622 };
2623 return &node.base;
2624 },
2625 .StrLit => {
2626 const buf = try rp.c.a().alloc(u8, tok.bytes.len + "\"\"".len);
2627 buf[0] = '"';
2628 writeEscapedString(buf[1..], tok.bytes);
2629 buf[buf.len - 1] = '"';
2630 const token = try appendToken(rp.c, .StringLiteral, buf);
2631 const node = try rp.c.a().create(ast.Node.StringLiteral);
2632 node.* = ast.Node.StringLiteral{
2633 .token = token,
2634 };
2635 return &node.base;
2636 },
2637 .Minus => {
2638 const node = try transCreateNodePrefixOp(
2639 rp.c,
2640 .Negation,
2641 .Minus,
2642 "-",
2643 );
2644 node.rhs = try parseCNumLit(rp, it.next().?, source_loc);
2645 return &node.base;
2646 },
2647 .NumLitInt, .NumLitFloat => {
2648 return parseCNumLit(rp, tok, source_loc);
2649 },
2650 .Identifier => return transCreateNodeIdentifier(rp.c, tok.bytes),
2651 .LParen => {
2652 _ = try appendToken(rp.c, .LParen, "(");
2653 const inner_node = try parseCExpr(rp, it, source_loc);
2654 _ = try appendToken(rp.c, .RParen, ")");
2655
2656 return inner_node; // TODO
2657 },
2658 else => return revertAndWarn(
2659 rp,
2660 error.UnsupportedTranslation,
2661 source_loc,
2662 "unable to translate C expr",
2663 .{},
2664 ),
2665 }
2666}
2667
2668fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation) ParseError!*ast.Node {
2669 var node = try parseCPrimaryExpr(rp, it, source_loc);
2670 while (true) {
2671 const tok = it.next().?;
2672 switch (tok.id) {
2673 .Dot => {
2674 const name_tok = it.next().?;
2675 if (name_tok.id != .Identifier)
2676 return revertAndWarn(
2677 rp,
2678 error.ParseError,
2679 source_loc,
2680 "unable to translate C expr",
2681 .{},
2682 );
2683
2684 const op_token = try appendToken(rp.c, .Period, ".");
2685 const rhs = try transCreateNodeIdentifier(rp.c, tok.bytes);
2686 const access_node = try rp.c.a().create(ast.Node.InfixOp);
2687 access_node.* = .{
2688 .op_token = op_token,
2689 .lhs = node,
2690 .op = .Period,
2691 .rhs = rhs,
2692 };
2693 node = &access_node.base;
2694 },
2695 .Shl => {
2696 const rhs_node = try parseCPrimaryExpr(rp, it, source_loc);
2697
2698 const op_token = try appendToken(rp.c, .AngleBracketAngleBracketLeft, "<<");
2699 const rhs = try parseCPrimaryExpr(rp, it, source_loc);
2700 const bitshift_node = try rp.c.a().create(ast.Node.InfixOp);
2701 bitshift_node.* = .{
2702 .op_token = op_token,
2703 .lhs = node,
2704 .op = .BitShiftLeft,
2705 .rhs = rhs,
2706 };
2707 node = &bitshift_node.base;
2708 },
2709 else => {
2710 _ = it.prev();
2711 return node;
2712 },
2713 }
2714 }
2715}
2716
2717fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation) ParseError!*ast.Node {
2718 const op_tok = it.next().?;
2719
2720 switch (op_tok.id) {
2721 else => {
2722 _ = it.prev();
2723 return try parseCSuffixOpExpr(rp, it, source_loc);
2724 },
2725 }
2726}
test/translate_c.zig+69-13
......@@ -214,6 +214,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
214214 \\ Clear: c_int,
215215 \\ },
216216 \\};
217 ,
217218 \\pub const OpenGLProcs = union_OpenGLProcs;
218219 });
219220
......@@ -280,9 +281,64 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
280281 \\ o,
281282 \\ p,
282283 \\};
284 ,
283285 \\pub const Baz = struct_Baz;
284286 });
285287
288 cases.add_2("#define a char literal",
289 \\#define A_CHAR 'a'
290 , &[_][]const u8{
291 \\pub const A_CHAR = 'a';
292 });
293
294 cases.add_2("comment after integer literal",
295 \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
296 , &[_][]const u8{
297 \\pub const SDL_INIT_VIDEO = 0x00000020;
298 });
299
300 cases.add_2("u integer suffix after hex literal",
301 \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
302 , &[_][]const u8{
303 \\pub const SDL_INIT_VIDEO = @as(c_uint, 0x00000020);
304 });
305
306 cases.add_2("l integer suffix after hex literal",
307 \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
308 , &[_][]const u8{
309 \\pub const SDL_INIT_VIDEO = @as(c_long, 0x00000020);
310 });
311
312 cases.add_2("ul integer suffix after hex literal",
313 \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
314 , &[_][]const u8{
315 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020);
316 });
317
318 cases.add_2("lu integer suffix after hex literal",
319 \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
320 , &[_][]const u8{
321 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020);
322 });
323
324 cases.add_2("ll integer suffix after hex literal",
325 \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
326 , &[_][]const u8{
327 \\pub const SDL_INIT_VIDEO = @as(c_longlong, 0x00000020);
328 });
329
330 cases.add_2("ull integer suffix after hex literal",
331 \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
332 , &[_][]const u8{
333 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020);
334 });
335
336 cases.add_2("llu integer suffix after hex literal",
337 \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
338 , &[_][]const u8{
339 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020);
340 });
341
286342 /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
287343
288344 cases.add_both("typedef of function in struct field",
......@@ -314,7 +370,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
314370 \\};
315371 });
316372
317 cases.add("macro with left shift",
373 cases.add_both("macro with left shift",
318374 \\#define REDISMODULE_READ (1<<0)
319375 , &[_][]const u8{
320376 \\pub const REDISMODULE_READ = 1 << 0;
......@@ -637,13 +693,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
637693 \\pub const A_CHAR = 97;
638694 });
639695
640 cases.add("#define an unsigned integer literal",
696 cases.add_both("#define an unsigned integer literal",
641697 \\#define CHANNEL_COUNT 24
642698 , &[_][]const u8{
643699 \\pub const CHANNEL_COUNT = 24;
644700 });
645701
646 cases.add("#define referencing another #define",
702 cases.add_both("#define referencing another #define",
647703 \\#define THING2 THING1
648704 \\#define THING1 1234
649705 , &[_][]const u8{
......@@ -692,7 +748,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
692748 \\}
693749 });
694750
695 cases.add("#define string",
751 cases.add_both("#define string",
696752 \\#define foo "a string"
697753 , &[_][]const u8{
698754 \\pub const foo = "a string";
......@@ -788,7 +844,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
788844 \\pub const FOO_CHAR = 63;
789845 });
790846
791 cases.add("macro with parens around negative number",
847 cases.add_both("macro with parens around negative number",
792848 \\#define LUA_GLOBALSINDEX (-10002)
793849 , &[_][]const u8{
794850 \\pub const LUA_GLOBALSINDEX = -10002;
......@@ -1732,7 +1788,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17321788 \\}
17331789 });
17341790
1735 cases.addC(
1791 cases.add_both(
17361792 "u integer suffix after 0 (zero) in macro definition",
17371793 "#define ZERO 0U",
17381794 &[_][]const u8{
......@@ -1740,7 +1796,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17401796 },
17411797 );
17421798
1743 cases.addC(
1799 cases.add_both(
17441800 "l integer suffix after 0 (zero) in macro definition",
17451801 "#define ZERO 0L",
17461802 &[_][]const u8{
......@@ -1748,7 +1804,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17481804 },
17491805 );
17501806
1751 cases.addC(
1807 cases.add_both(
17521808 "ul integer suffix after 0 (zero) in macro definition",
17531809 "#define ZERO 0UL",
17541810 &[_][]const u8{
......@@ -1756,7 +1812,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17561812 },
17571813 );
17581814
1759 cases.addC(
1815 cases.add_both(
17601816 "lu integer suffix after 0 (zero) in macro definition",
17611817 "#define ZERO 0LU",
17621818 &[_][]const u8{
......@@ -1764,7 +1820,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17641820 },
17651821 );
17661822
1767 cases.addC(
1823 cases.add_both(
17681824 "ll integer suffix after 0 (zero) in macro definition",
17691825 "#define ZERO 0LL",
17701826 &[_][]const u8{
......@@ -1772,7 +1828,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17721828 },
17731829 );
17741830
1775 cases.addC(
1831 cases.add_both(
17761832 "ull integer suffix after 0 (zero) in macro definition",
17771833 "#define ZERO 0ULL",
17781834 &[_][]const u8{
......@@ -1780,7 +1836,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17801836 },
17811837 );
17821838
1783 cases.addC(
1839 cases.add_both(
17841840 "llu integer suffix after 0 (zero) in macro definition",
17851841 "#define ZERO 0LLU",
17861842 &[_][]const u8{
......@@ -1788,7 +1844,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17881844 },
17891845 );
17901846
1791 cases.addC(
1847 cases.addC(//todo
17921848 "bitwise not on u-suffixed 0 (zero) in macro definition",
17931849 "#define NOT_ZERO (~0U)",
17941850 &[_][]const u8{