Commit 73a53fa263

Vexu <git@vexu.eu>
2020-01-04 19:37:04
std-c outline parser
1 parent e1b01d3
Changed files (2)
lib
lib/std/c/parse.zig
@@ -0,0 +1,296 @@
+const std = @import("../std.zig");
+const assert = std.debug.assert;
+const Allocator = std.mem.Allocator;
+const ast = std.c.ast;
+const Tree = ast.Tree;
+const TokenIndex = ast.TokenIndex;
+const Token = std.c.Token;
+const TokenIterator = ast.Tree.TokenList.Iterator;
+
+pub const Error = error{ParseError} || Allocator.Error;
+
+/// Result should be freed with tree.deinit() when there are
+/// no more references to any of the tokens or nodes.
+pub fn parse(allocator: *Allocator, source: []const u8) !*Tree {
+    const tree = blk: {
+        // This block looks unnecessary, but is a "foot-shield" to prevent the SegmentedLists
+        // from being initialized with a pointer to this `arena`, which is created on
+        // the stack. Following code should instead refer to `&tree.arena_allocator`, a
+        // pointer to data which lives safely on the heap and will outlive `parse`.
+        var arena = std.heap.ArenaAllocator.init(allocator);
+        errdefer arena.deinit();
+        const tree = try arena.allocator.create(ast.Tree);
+        tree.* = .{
+            .root_node = undefined,
+            .arena_allocator = arena,
+            .tokens = undefined,
+            .sources = undefined,
+        };
+        break :blk tree;
+    };
+    errdefer tree.deinit();
+    const arena = &tree.arena_allocator.allocator;
+
+    tree.tokens = ast.Tree.TokenList.init(arena);
+    tree.sources = ast.Tree.SourceList.init(arena);
+
+    var tokenizer = std.zig.Tokenizer.init(source);
+    while (true) {
+        const tree_token = try tree.tokens.addOne();
+        tree_token.* = tokenizer.next();
+        if (tree_token.id == .Eof) break;
+    }
+    // TODO preprocess here
+    var it = tree.tokens.iterator(0);
+
+    while (true) {
+        const tok = it.peek().?.id;
+        switch (id) {
+            .LineComment,
+            .MultiLineComment,
+            => {
+                _ = it.next();
+            },
+            else => break,
+        }
+    }
+
+    tree.root_node = try parseRoot(arena, &it, tree);
+    return tree;
+}
+
+/// Root <- ExternalDeclaration* eof
+fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error!*Node {
+    const node = try arena.create(ast.Root);
+    node.* = .{
+        .decls = ast.Node.DeclList.init(arena),
+        .eof_token = undefined,
+    };
+    while (parseExternalDeclarations(arena, it, tree) catch |err| switch (err) {
+        error.OutOfMemory => return error.OutOfMemory,
+        error.ParseError => return node,
+    }) |decl| {
+        try node.decls.push(decl);
+    }
+    node.eof_token = eatToken(it, .Eof) orelse {
+        try tree.errors.push(.{
+            .ExpectedDecl = .{ .token = it.index },
+        });
+        return node;
+    };
+    return node;
+}
+
+/// ExternalDeclaration
+///     <- Declaration
+///     / DeclarationSpecifiers Declarator Declaration* CompoundStmt
+fn parseExternalDeclarations(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
+    if (try parseDeclaration(arena, it, tree)) |decl| {}
+    return null;
+}
+
+/// Declaration
+///     <- DeclarationSpecifiers (Declarator (EQUAL Initializer)?)* SEMICOLON
+///     \ StaticAssertDeclaration
+fn parseDeclaration(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {}
+
+/// StaticAssertDeclaration <- Keyword_static_assert LPAREN ConstExpr COMMA STRINGLITERAL RPAREN SEMICOLON
+fn parseStaticAssertDeclaration(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {}
+
+/// DeclarationSpecifiers
+///     <- StorageClassSpecifier DeclarationSpecifiers?
+///     / TypeSpecifier DeclarationSpecifiers?
+///     / TypeQualifier DeclarationSpecifiers?
+///     / FunctionSpecifier DeclarationSpecifiers?
+///     / AlignmentSpecifier DeclarationSpecifiers?
+fn parseDeclarationSpecifiers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// StorageClassSpecifier
+///     <- Keyword_typedef / Keyword_extern / Keyword_static / Keyword_thread_local / Keyword_auto / Keyword_register
+fn parseStorageClassSpecifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// TypeSpecifier
+///     <- Keyword_void / Keyword_char / Keyword_short / Keyword_int / Keyword_long / Keyword_float / Keyword_double
+///     / Keyword_signed / Keyword_unsigned / Keyword_bool / Keyword_complex / Keyword_imaginary /
+///     / Keyword_atomic LPAREN TypeName RPAREN
+///     / EnumSpecifier
+///     / RecordSpecifier
+///     / IDENTIFIER // typedef name
+fn parseTypeSpecifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// TypeQualifier <- Keyword_const / Keyword_restrict / Keyword_volatile / Keyword_atomic
+fn parseTypeQualifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// FunctionSpecifier <- Keyword_inline / Keyword_noreturn
+fn parseFunctionSpecifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// AlignmentSpecifier <- Keyword_alignas LPAREN (TypeName / ConstExpr) RPAREN
+fn parseAlignmentSpecifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// EnumSpecifier <- Keyword_enum IDENTIFIER? (LBRACE EnumField RBRACE)?
+fn parseEnumSpecifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// EnumField <- IDENTIFIER (EQUAL ConstExpr)? (COMMA EnumField) COMMA?
+fn parseEnumField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// RecordSpecifier <- (Keyword_struct / Keyword_union) IDENTIFIER? (LBRACE RecordField+ RBRACE)?
+fn parseRecordSpecifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// RecordField
+///     <- SpecifierQualifer (RecordDeclarator (COMMA RecordDeclarator))? SEMICOLON
+///     \ StaticAssertDeclaration
+fn parseRecordField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// TypeName
+///     <- SpecifierQualifer AbstractDeclarator?
+fn parseTypeName(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// SpecifierQualifer
+///     <- TypeSpecifier SpecifierQualifer?
+///     / TypeQualifier SpecifierQualifer?
+fn parseSpecifierQualifer(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// RecordDeclarator <- Declarator? (COLON ConstExpr)?
+fn parseRecordDeclarator(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// Declarator <- Pointer? DirectDeclarator
+fn parseDeclarator(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// Pointer <- ASTERISK TypeQualifier* Pointer?
+fn parsePointer(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// DirectDeclarator
+///     <- IDENTIFIER
+///     / LPAREN Declarator RPAREN
+///     / DirectDeclarator LBRACKET (ASTERISK / BracketDeclarator)? RBRACKET
+///     / DirectDeclarator LPAREN (ParamDecl (COMMA ParamDecl)* (COMMA ELLIPSIS)?)? RPAREN
+fn parseDirectDeclarator(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// BracketDeclarator
+///     <- Keyword_static TypeQualifier* AssignmentExpr
+///     / TypeQualifier+ (ASTERISK / Keyword_static AssignmentExpr)
+///     / TypeQualifier+ AssignmentExpr?
+///     / AssignmentExpr
+fn parseBracketDeclarator(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// ParamDecl <- DeclarationSpecifiers (Declarator / AbstractDeclarator)
+fn parseParamDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// AbstractDeclarator <- Pointer? DirectAbstractDeclarator?
+fn parseAbstractDeclarator(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// DirectAbstractDeclarator
+///     <- IDENTIFIER
+///     / LPAREN DirectAbstractDeclarator RPAREN
+///     / DirectAbstractDeclarator? LBRACKET (ASTERISK / BracketDeclarator)? RBRACKET
+///     / DirectAbstractDeclarator? LPAREN (ParamDecl (COMMA ParamDecl)* (COMMA ELLIPSIS)?)? RPAREN
+fn parseDirectAbstractDeclarator(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// Expr <- AssignmentExpr (COMMA Expr)*
+fn parseExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// AssignmentExpr
+///     <- ConditionalExpr
+///     / UnaryExpr (EQUAL / ASTERISKEQUAL / SLASHEQUAL / PERCENTEQUAL / PLUSEQUAL / MINUSEQUA /
+///     / ANGLEBRACKETANGLEBRACKETLEFTEQUAL / ANGLEBRACKETANGLEBRACKETRIGHTEQUAL /
+///     / AMPERSANDEQUAL / CARETEQUAL / PIPEEQUAL) AssignmentExpr
+fn parseAssignmentExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// ConstExpr <- ConditionalExpr
+/// ConditionalExpr <- LogicalOrExpr (QUESTIONMARK Expr COLON ConditionalExpr)?
+fn parseConditionalExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// LogicalOrExpr <- LogicalAndExpr (PIPEPIPE LogicalOrExpr)*
+fn parseLogicalOrExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// LogicalAndExpr <- BinOrExpr (AMPERSANDAMPERSAND LogicalAndExpr)*
+fn parseLogicalAndExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// BinOrExpr <- BinXorExpr (PIPE BinOrExpr)*
+fn parseBinOrExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// BinXorExpr <- BinAndExpr (CARET BinXorExpr)*
+fn parseBinXorExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// BinAndExpr <- EqualityExpr (AMPERSAND BinAndExpr)*
+fn parseBinAndExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// EqualityExpr <- ComparisionExpr ((EQUALEQUAL / BANGEQUAL) EqualityExpr)*
+fn parseEqualityExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// ComparisionExpr <- ShiftExpr (ANGLEBRACKETLEFT / ANGLEBRACKETLEFTEQUAL /ANGLEBRACKETRIGHT / ANGLEBRACKETRIGHTEQUAL) ComparisionExpr)*
+fn parseComparisionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// ShiftExpr <- AdditiveExpr (ANGLEBRACKETANGLEBRACKETLEFT / ANGLEBRACKETANGLEBRACKETRIGHT) ShiftExpr)*
+fn parseShiftExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// AdditiveExpr <- MultiplicativeExpr (PLUS / MINUS) AdditiveExpr)*
+fn parseAdditiveExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// MultiplicativeExpr <- UnaryExpr (ASTERISK / SLASH / PERCENT) MultiplicativeExpr)*
+fn parseMultiplicativeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// UnaryExpr
+///     <- LPAREN TypeName RPAREN UnaryExpr
+///     / Keyword_sizeof LAPERN TypeName RPAREN
+///     / Keyword_sizeof UnaryExpr
+///     / Keyword_alignof LAPERN TypeName RPAREN
+///     / (AMPERSAND / ASTERISK / PLUS / PLUSPLUS / MINUS / MINUSMINUS / TILDE / BANG) UnaryExpr
+///     / PrimaryExpr PostFixExpr*
+fn parseUnaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// PrimaryExpr
+///     <- IDENTIFIER
+///     / INTEGERLITERAL / FLITERAL / STRINGLITERAL / CHARLITERAL
+///     / LPAREN Expr RPAREN
+///     / Keyword_generic LPAREN AssignmentExpr (COMMA Generic)+ RPAREN
+fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// Generic
+///     <- TypeName COLON AssignmentExpr
+///     / Keyword_default COLON AssignmentExpr
+fn parseGeneric(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// PostFixExpr
+///     <- LPAREN TypeName RPAREN LBRACE Initializers RBRACE
+///     / LBRACKET Expr RBRACKET
+///     / LPAREN (AssignmentExpr (COMMA AssignmentExpr)*)? RPAREN
+///     / (PERIOD / ARROW) IDENTIFIER
+///     / (PLUSPLUS / MINUSMINUS)
+fn parsePostFixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// Initializers <- ((Designator+ EQUAL)? Initializer COMMA)* (Designator+ EQUAL)? Initializer COMMA?
+fn parseInitializers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// Initializer
+///     <- LBRACE Initializers RBRACE
+///     / AssignmentExpr
+fn parseInitializer(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// Designator
+///     <- LBRACKET Initializers RBRACKET
+///     / PERIOD IDENTIFIER
+fn parseDesignator(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// CompoundStmt <- LBRACE (Declaration / Stmt)* RBRACE
+fn parseCompoundStmt(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// Stmt
+///     <- CompoundStmt
+///     / Keyword_if LPAREN Expr RPAREN Stmt (Keyword_ELSE Stmt)?
+///     / Keyword_switch LPAREN Expr RPAREN Stmt
+///     / Keyword_while LPAREN Expr RPAREN Stmt
+///     / Keyword_do statement Keyword_while LPAREN Expr RPAREN SEMICOLON
+///     / Keyword_for LPAREN (Declaration / ExprStmt) ExprStmt Expr? RPAREN Stmt
+///     / Keyword_default COLON Stmt
+///     / Keyword_case ConstExpr COLON Stmt
+///     / Keyword_goto IDENTIFIER SEMICOLON
+///     / Keyword_continue SEMICOLON
+///     / Keyword_break SEMICOLON
+///     / Keyword_return Expr? SEMICOLON
+///     / IDENTIFIER COLON Stmt
+///     / ExprStmt
+fn parseStmt(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
+
+/// ExprStmt <- Expr? SEMICOLON
+fn parseExprStmt(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {}
lib/std/c.zig
@@ -5,6 +5,7 @@ const page_size = std.mem.page_size;
 const tokenizer = @import("c/tokenizer.zig");
 pub const Token = tokenizer.Token;
 pub const Tokenizer = tokenizer.Tokenizer;
+pub const parse = @import("c/parse.zig").parse;
 pub const ast = @import("c/ast.zig");
 
 pub usingnamespace @import("os/bits.zig");