| author | |
| committer | |
| log | 174baa49bda0d4ce1dfc99555d7e41cd86a49513 |
| tree | 28eb533d48c98f0680905692a123eb21755340bf |
| parent | c36cd9d313d5069898233188f72b0d2b5fe8f349 |
9 files changed, 151 insertions(+), 101 deletions(-)
CMakeLists.txt+5-4| ... | @@ -21,14 +21,15 @@ include_directories( | ... | @@ -21,14 +21,15 @@ include_directories( |
| 21 | ) | 21 | ) |
| 22 | 22 | ||
| 23 | set(GRAMMAR_TXT "${CMAKE_BINARY_DIR}/simple.txt") | 23 | set(GRAMMAR_TXT "${CMAKE_BINARY_DIR}/simple.txt") |
| 24 | set(PARSER_CPP "${CMAKE_BINARY_DIR}/parser.cpp") | 24 | set(PARSER_GENERATED_CPP "${CMAKE_BINARY_DIR}/parser_generated.cpp") |
| 25 | 25 | ||
| 26 | set(ZIG_SOURCES | 26 | set(ZIG_SOURCES |
| 27 | "${CMAKE_SOURCE_DIR}/src/main.cpp" | 27 | "${CMAKE_SOURCE_DIR}/src/main.cpp" |
| 28 | "${CMAKE_SOURCE_DIR}/src/util.cpp" | 28 | "${CMAKE_SOURCE_DIR}/src/util.cpp" |
| 29 | "${CMAKE_SOURCE_DIR}/src/buffer.cpp" | 29 | "${CMAKE_SOURCE_DIR}/src/buffer.cpp" |
| 30 | "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" | 30 | "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" |
| 31 | ${PARSER_CPP} | 31 | "${CMAKE_SOURCE_DIR}/src/parser.cpp" |
| 32 | ${PARSER_GENERATED_CPP} | ||
| 32 | ) | 33 | ) |
| 33 | 34 | ||
| 34 | set(PARSERGEN_SOURCES | 35 | set(PARSERGEN_SOURCES |
| ... | @@ -68,8 +69,8 @@ set_target_properties(parsergen PROPERTIES | ... | @@ -68,8 +69,8 @@ set_target_properties(parsergen PROPERTIES |
| 68 | 69 | ||
| 69 | 70 | ||
| 70 | add_custom_command( | 71 | add_custom_command( |
| 71 | OUTPUT ${PARSER_CPP} | 72 | OUTPUT ${PARSER_GENERATED_CPP} |
| 72 | COMMAND parsergen ARGS ${GRAMMAR_TXT} ${PARSER_CPP} | 73 | COMMAND parsergen ARGS ${GRAMMAR_TXT} ${PARSER_GENERATED_CPP} |
| 73 | DEPENDS ${GRAMMAR_TXT} ${PARSERGEN_SOURCES} | 74 | DEPENDS ${GRAMMAR_TXT} ${PARSERGEN_SOURCES} |
| 74 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} | 75 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} |
| 75 | ) | 76 | ) |
README.md+21-15| ... | @@ -19,7 +19,7 @@ readable, safe, optimal, and concise code to solve any computing problem. | ... | @@ -19,7 +19,7 @@ readable, safe, optimal, and concise code to solve any computing problem. |
| 19 | * Eliminate the need for C headers (when using zig internally). | 19 | * Eliminate the need for C headers (when using zig internally). |
| 20 | * Ability to declare dependencies as Git URLS with commit locking (can | 20 | * Ability to declare dependencies as Git URLS with commit locking (can |
| 21 | provide a tag or sha1). | 21 | provide a tag or sha1). |
| 22 | * Rust-style enums. | 22 | * Tagged union enum type. |
| 23 | * Opinionated when it makes life easier. | 23 | * Opinionated when it makes life easier. |
| 24 | - Tab character in source code is a compile error. | 24 | - Tab character in source code is a compile error. |
| 25 | - Whitespace at the end of line is a compile error. | 25 | - Whitespace at the end of line is a compile error. |
| ... | @@ -32,23 +32,29 @@ readable, safe, optimal, and concise code to solve any computing problem. | ... | @@ -32,23 +32,29 @@ readable, safe, optimal, and concise code to solve any computing problem. |
| 32 | * Hello, world. | 32 | * Hello, world. |
| 33 | - Build AST | 33 | - Build AST |
| 34 | - Code Gen | 34 | - Code Gen |
| 35 | - Produce .o file. | ||
| 36 | * Produce executable file instead of .o file. | ||
| 37 | * Add debugging symbols. | ||
| 38 | * Debug/Release mode. | ||
| 35 | * C style comments. | 39 | * C style comments. |
| 36 | * Unit tests. | 40 | * Unit tests. |
| 37 | * Simple .so library | 41 | * Simple .so library |
| 38 | * How should the Widget use case be solved? In Genesis I'm using C++ and inheritance. | 42 | * How should the Widget use case be solved? In Genesis I'm using C++ and inheritance. |
| 39 | 43 | ||
| 40 | ## Grammar | 44 | ### Primitive Numeric Types: |
| 41 | 45 | ||
| 42 | ``` | 46 | zig | C equivalent | Description |
| 43 | Root : FnDecl* | 47 | -------|--------------|------------------------------- |
| 44 | FnDecl : TokenFn TokenSymbol TokenLParen list(ParamDecl, TokenComma, 0) TokenRParen (TokenArrow Type)? Block | 48 | i8 | int8_t | signed 8-bit integer |
| 45 | ParamDecl : TokenSymbol TokenColon Type | 49 | u8 | uint8_t | unsigned 8-bit integer |
| 46 | Type : TokenSymbol | PointerType | 50 | i16 | int16_t | signed 16-bit integer |
| 47 | PointerType : TokenStar (TokenConst | TokenMut) Type | 51 | u16 | uint16_t | unsigned 16-bit integer |
| 48 | Block : TokenLBrace Statement* Expression? TokenRBrace | 52 | i32 | int32_t | signed 32-bit integer |
| 49 | Statement : ExpressionStatement | ReturnStatement | 53 | u32 | uint32_t | unsigned 32-bit integer |
| 50 | ExpressionStatement : Expression TokenSemicolon | 54 | i64 | int64_t | signed 64-bit integer |
| 51 | ReturnStatement : TokenReturn Expression TokenSemicolon | 55 | u64 | uint64_t | unsigned 64-bit integer |
| 52 | Expression : TokenNumber | TokenString | FnCall | 56 | f32 | float | 32-bit IEE754 floating point |
| 53 | FnCall : TokenSymbol TokenLParen list(Expression, TokenComma, 0) TokenRParen | 57 | f64 | double | 64-bit IEE754 floating point |
| 54 | ``` | 58 | f128 | long double | 128-bit IEE754 floating point |
| 59 | isize | ssize_t | signed pointer sized integer | ||
| 60 | usize | size_t | unsigned pointer sized integer |
src/main.cpp-77| ... | @@ -15,7 +15,6 @@ | ... | @@ -15,7 +15,6 @@ |
| 15 | #include <stdio.h> | 15 | #include <stdio.h> |
| 16 | #include <string.h> | 16 | #include <string.h> |
| 17 | #include <stdlib.h> | 17 | #include <stdlib.h> |
| 18 | #include <stdarg.h> | ||
| 19 | #include <limits.h> | 18 | #include <limits.h> |
| 20 | #include <stdint.h> | 19 | #include <stdint.h> |
| 21 | #include <errno.h> | 20 | #include <errno.h> |
| ... | @@ -50,82 +49,6 @@ static Buf *fetch_file(FILE *f) { | ... | @@ -50,82 +49,6 @@ static Buf *fetch_file(FILE *f) { |
| 50 | return buf; | 49 | return buf; |
| 51 | } | 50 | } |
| 52 | 51 | ||
| 53 | void ast_error(Token *token, const char *format, ...) { | ||
| 54 | int line = token->start_line + 1; | ||
| 55 | int column = token->start_column + 1; | ||
| 56 | |||
| 57 | va_list ap; | ||
| 58 | va_start(ap, format); | ||
| 59 | fprintf(stderr, "Error: Line %d, column %d: ", line, column); | ||
| 60 | vfprintf(stderr, format, ap); | ||
| 61 | fprintf(stderr, "\n"); | ||
| 62 | va_end(ap); | ||
| 63 | exit(EXIT_FAILURE); | ||
| 64 | } | ||
| 65 | |||
| 66 | static const char *node_type_str(NodeType node_type) { | ||
| 67 | switch (node_type) { | ||
| 68 | case NodeTypeRoot: | ||
| 69 | return "Root"; | ||
| 70 | case NodeTypeFnDecl: | ||
| 71 | return "FnDecl"; | ||
| 72 | case NodeTypeParamDecl: | ||
| 73 | return "ParamDecl"; | ||
| 74 | case NodeTypeType: | ||
| 75 | return "Type"; | ||
| 76 | case NodeTypePointerType: | ||
| 77 | return "PointerType"; | ||
| 78 | case NodeTypeBlock: | ||
| 79 | return "Block"; | ||
| 80 | case NodeTypeStatement: | ||
| 81 | return "Statement"; | ||
| 82 | case NodeTypeExpressionStatement: | ||
| 83 | return "ExpressionStatement"; | ||
| 84 | case NodeTypeReturnStatement: | ||
| 85 | return "ReturnStatement"; | ||
| 86 | case NodeTypeExpression: | ||
| 87 | return "Expression"; | ||
| 88 | case NodeTypeFnCall: | ||
| 89 | return "FnCall"; | ||
| 90 | } | ||
| 91 | zig_panic("unreachable"); | ||
| 92 | } | ||
| 93 | |||
| 94 | static void ast_print(AstNode *node, int indent) { | ||
| 95 | for (int i = 0; i < indent; i += 1) { | ||
| 96 | fprintf(stderr, " "); | ||
| 97 | } | ||
| 98 | |||
| 99 | switch (node->type) { | ||
| 100 | case NodeTypeRoot: | ||
| 101 | fprintf(stderr, "%s\n", node_type_str(node->type)); | ||
| 102 | for (int i = 0; i < node->data.root.fn_decls.length; i += 1) { | ||
| 103 | AstNode *child = node->data.root.fn_decls.at(i); | ||
| 104 | ast_print(child, indent + 2); | ||
| 105 | } | ||
| 106 | break; | ||
| 107 | case NodeTypeFnDecl: | ||
| 108 | { | ||
| 109 | Buf *name_buf = &node->data.fn_decl.name; | ||
| 110 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf)); | ||
| 111 | |||
| 112 | for (int i = 0; i < node->data.fn_decl.params.length; i += 1) { | ||
| 113 | AstNode *child = node->data.fn_decl.params.at(i); | ||
| 114 | ast_print(child, indent + 2); | ||
| 115 | } | ||
| 116 | |||
| 117 | ast_print(node->data.fn_decl.return_type, indent + 2); | ||
| 118 | |||
| 119 | ast_print(node->data.fn_decl.body, indent + 2); | ||
| 120 | |||
| 121 | break; | ||
| 122 | } | ||
| 123 | default: | ||
| 124 | fprintf(stderr, "%s\n", node_type_str(node->type)); | ||
| 125 | break; | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | char cur_dir[1024]; | 52 | char cur_dir[1024]; |
| 130 | 53 | ||
| 131 | int main(int argc, char **argv) { | 54 | int main(int argc, char **argv) { |
src/parser.cpp created+80| ... | @@ -0,0 +1,80 @@ | ||
| 1 | #include "parser.hpp" | ||
| 2 | |||
| 3 | #include <stdarg.h> | ||
| 4 | #include <stdio.h> | ||
| 5 | |||
| 6 | void ast_error(Token *token, const char *format, ...) { | ||
| 7 | int line = token->start_line + 1; | ||
| 8 | int column = token->start_column + 1; | ||
| 9 | |||
| 10 | va_list ap; | ||
| 11 | va_start(ap, format); | ||
| 12 | fprintf(stderr, "Error: Line %d, column %d: ", line, column); | ||
| 13 | vfprintf(stderr, format, ap); | ||
| 14 | fprintf(stderr, "\n"); | ||
| 15 | va_end(ap); | ||
| 16 | exit(EXIT_FAILURE); | ||
| 17 | } | ||
| 18 | |||
| 19 | const char *node_type_str(NodeType node_type) { | ||
| 20 | switch (node_type) { | ||
| 21 | case NodeTypeRoot: | ||
| 22 | return "Root"; | ||
| 23 | case NodeTypeFnDecl: | ||
| 24 | return "FnDecl"; | ||
| 25 | case NodeTypeParamDecl: | ||
| 26 | return "ParamDecl"; | ||
| 27 | case NodeTypeType: | ||
| 28 | return "Type"; | ||
| 29 | case NodeTypePointerType: | ||
| 30 | return "PointerType"; | ||
| 31 | case NodeTypeBlock: | ||
| 32 | return "Block"; | ||
| 33 | case NodeTypeStatement: | ||
| 34 | return "Statement"; | ||
| 35 | case NodeTypeExpressionStatement: | ||
| 36 | return "ExpressionStatement"; | ||
| 37 | case NodeTypeReturnStatement: | ||
| 38 | return "ReturnStatement"; | ||
| 39 | case NodeTypeExpression: | ||
| 40 | return "Expression"; | ||
| 41 | case NodeTypeFnCall: | ||
| 42 | return "FnCall"; | ||
| 43 | } | ||
| 44 | zig_panic("unreachable"); | ||
| 45 | } | ||
| 46 | |||
| 47 | void ast_print(AstNode *node, int indent) { | ||
| 48 | for (int i = 0; i < indent; i += 1) { | ||
| 49 | fprintf(stderr, " "); | ||
| 50 | } | ||
| 51 | |||
| 52 | switch (node->type) { | ||
| 53 | case NodeTypeRoot: | ||
| 54 | fprintf(stderr, "%s\n", node_type_str(node->type)); | ||
| 55 | for (int i = 0; i < node->data.root.fn_decls.length; i += 1) { | ||
| 56 | AstNode *child = node->data.root.fn_decls.at(i); | ||
| 57 | ast_print(child, indent + 2); | ||
| 58 | } | ||
| 59 | break; | ||
| 60 | case NodeTypeFnDecl: | ||
| 61 | { | ||
| 62 | Buf *name_buf = &node->data.fn_decl.name; | ||
| 63 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf)); | ||
| 64 | |||
| 65 | for (int i = 0; i < node->data.fn_decl.params.length; i += 1) { | ||
| 66 | AstNode *child = node->data.fn_decl.params.at(i); | ||
| 67 | ast_print(child, indent + 2); | ||
| 68 | } | ||
| 69 | |||
| 70 | ast_print(node->data.fn_decl.return_type, indent + 2); | ||
| 71 | |||
| 72 | ast_print(node->data.fn_decl.body, indent + 2); | ||
| 73 | |||
| 74 | break; | ||
| 75 | } | ||
| 76 | default: | ||
| 77 | fprintf(stderr, "%s\n", node_type_str(node->type)); | ||
| 78 | break; | ||
| 79 | } | ||
| 80 | } | ||
src/parser.hpp+5| ... | @@ -82,6 +82,11 @@ struct AstNode { | ... | @@ -82,6 +82,11 @@ struct AstNode { |
| 82 | __attribute__ ((format (printf, 2, 3))) | 82 | __attribute__ ((format (printf, 2, 3))) |
| 83 | void ast_error(Token *token, const char *format, ...); | 83 | void ast_error(Token *token, const char *format, ...); |
| 84 | 84 | ||
| 85 | // This function is provided by generated code, generated by parsergen.cpp | ||
| 85 | AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens); | 86 | AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens); |
| 86 | 87 | ||
| 88 | const char *node_type_str(NodeType node_type); | ||
| 89 | |||
| 90 | void ast_print(AstNode *node, int indent); | ||
| 91 | |||
| 87 | #endif | 92 | #endif |
src/parsergen.cpp+25-2| ... | @@ -190,12 +190,17 @@ struct RuleNode { | ... | @@ -190,12 +190,17 @@ struct RuleNode { |
| 190 | enum ParserStateType { | 190 | enum ParserStateType { |
| 191 | ParserStateTypeError, | 191 | ParserStateTypeError, |
| 192 | ParserStateTypeOk, | 192 | ParserStateTypeOk, |
| 193 | ParserStateTypeCapture, | ||
| 193 | }; | 194 | }; |
| 194 | 195 | ||
| 195 | struct ParserStateError { | 196 | struct ParserStateError { |
| 196 | Buf *msg; | 197 | Buf *msg; |
| 197 | }; | 198 | }; |
| 198 | 199 | ||
| 200 | struct ParserStateCapture { | ||
| 201 | Buf *body; | ||
| 202 | }; | ||
| 203 | |||
| 199 | struct ParserState { | 204 | struct ParserState { |
| 200 | ParserStateType type; | 205 | ParserStateType type; |
| 201 | // One for each token ID. | 206 | // One for each token ID. |
| ... | @@ -203,6 +208,7 @@ struct ParserState { | ... | @@ -203,6 +208,7 @@ struct ParserState { |
| 203 | int index; | 208 | int index; |
| 204 | union { | 209 | union { |
| 205 | ParserStateError error; | 210 | ParserStateError error; |
| 211 | ParserStateCapture capture; | ||
| 206 | }; | 212 | }; |
| 207 | }; | 213 | }; |
| 208 | 214 | ||
| ... | @@ -278,6 +284,8 @@ static void gen(Gen *g, RuleNode *node) { | ... | @@ -278,6 +284,8 @@ static void gen(Gen *g, RuleNode *node) { |
| 278 | RuleNode *child = node->tuple.children.at(i); | 284 | RuleNode *child = node->tuple.children.at(i); |
| 279 | gen(g, child); | 285 | gen(g, child); |
| 280 | } | 286 | } |
| 287 | g->cur_state->type = ParserStateTypeCapture; | ||
| 288 | g->cur_state->capture.body = &node->tuple.body; | ||
| 281 | } | 289 | } |
| 282 | break; | 290 | break; |
| 283 | case RuleNodeTypeMany: | 291 | case RuleNodeTypeMany: |
| ... | @@ -598,7 +606,8 @@ int main(int argc, char **argv) { | ... | @@ -598,7 +606,8 @@ int main(int argc, char **argv) { |
| 598 | g.cur_state = create_state(&g, ParserStateTypeOk); | 606 | g.cur_state = create_state(&g, ParserStateTypeOk); |
| 599 | gen(&g, g.root); | 607 | gen(&g, g.root); |
| 600 | 608 | ||
| 601 | fprintf(out_f, "/* This file is auto-generated by parsergen.cpp */\n"); | 609 | fprintf(out_f, "/* This file is generated by parsergen.cpp */\n"); |
| 610 | fprintf(out_f, "\n"); | ||
| 602 | fprintf(out_f, "#include \"src/parser.hpp\"\n"); | 611 | fprintf(out_f, "#include \"src/parser.hpp\"\n"); |
| 603 | fprintf(out_f, "#include <stdio.h>\n"); | 612 | fprintf(out_f, "#include <stdio.h>\n"); |
| 604 | 613 | ||
| ... | @@ -616,6 +625,17 @@ int main(int argc, char **argv) { | ... | @@ -616,6 +625,17 @@ int main(int argc, char **argv) { |
| 616 | fprintf(out_f, "static_assert(TokenId%s == %d, \"wrong token id\");\n", | 625 | fprintf(out_f, "static_assert(TokenId%s == %d, \"wrong token id\");\n", |
| 617 | buf_ptr(&token->name), token->id); | 626 | buf_ptr(&token->name), token->id); |
| 618 | } | 627 | } |
| 628 | fprintf(out_f, "\n"); | ||
| 629 | |||
| 630 | /* TODO | ||
| 631 | fprintf(out_f, "struct ParserGenNode{\n"); | ||
| 632 | fprintf(out_f, " union {\n"); | ||
| 633 | fprintf(out_f, " [%d];\n", biggest_tuple_len); | ||
| 634 | fprintf(out_f, " Token *token;\n"); | ||
| 635 | fprintf(out_f, " };\n"); | ||
| 636 | fprintf(out_f, "};\n"); | ||
| 637 | fprintf(out_f, "\n"); | ||
| 638 | */ | ||
| 619 | 639 | ||
| 620 | fprintf(out_f, "AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens) {\n"); | 640 | fprintf(out_f, "AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens) {\n"); |
| 621 | 641 | ||
| ... | @@ -644,7 +664,6 @@ int main(int argc, char **argv) { | ... | @@ -644,7 +664,6 @@ int main(int argc, char **argv) { |
| 644 | for (int i = 0; i < g.transition_table.length; i += 1) { | 664 | for (int i = 0; i < g.transition_table.length; i += 1) { |
| 645 | ParserState *state = g.transition_table.at(i); | 665 | ParserState *state = g.transition_table.at(i); |
| 646 | fprintf(out_f, " case %d:\n", i); | 666 | fprintf(out_f, " case %d:\n", i); |
| 647 | fprintf(out_f, " fprintf(stderr, \"state = %%d\\n\", state);\n"); | ||
| 648 | switch (state->type) { | 667 | switch (state->type) { |
| 649 | case ParserStateTypeError: | 668 | case ParserStateTypeError: |
| 650 | fprintf(out_f, " ast_error(token, \"%s\");\n", buf_ptr(state->error.msg)); | 669 | fprintf(out_f, " ast_error(token, \"%s\");\n", buf_ptr(state->error.msg)); |
| ... | @@ -655,6 +674,10 @@ int main(int argc, char **argv) { | ... | @@ -655,6 +674,10 @@ int main(int argc, char **argv) { |
| 655 | state->index, g.transition_table.length); | 674 | state->index, g.transition_table.length); |
| 656 | fprintf(out_f, " state = transition[%d][token->id];\n", state->index); | 675 | fprintf(out_f, " state = transition[%d][token->id];\n", state->index); |
| 657 | break; | 676 | break; |
| 677 | case ParserStateTypeCapture: | ||
| 678 | // TODO fprintf(out_f, " %s\n", buf_ptr(state->capture.body)); | ||
| 679 | fprintf(out_f, " state = transition[%d][token->id];\n", state->index); | ||
| 680 | break; | ||
| 658 | } | 681 | } |
| 659 | fprintf(out_f, " break;\n"); | 682 | fprintf(out_f, " break;\n"); |
| 660 | } | 683 | } |
src/tokenizer.cpp+7| ... | @@ -1,3 +1,10 @@ | ... | @@ -1,3 +1,10 @@ |
| 1 | /* | ||
| 2 | * Copyright (c) 2015 Andrew Kelley | ||
| 3 | * | ||
| 4 | * This file is part of zig, which is MIT licensed. | ||
| 5 | * See http://opensource.org/licenses/MIT | ||
| 6 | */ | ||
| 7 | |||
| 1 | #include "tokenizer.hpp" | 8 | #include "tokenizer.hpp" |
| 2 | #include "util.hpp" | 9 | #include "util.hpp" |
| 3 | 10 |
src/tokenizer.hpp+7| ... | @@ -1,3 +1,10 @@ | ... | @@ -1,3 +1,10 @@ |
| 1 | /* | ||
| 2 | * Copyright (c) 2015 Andrew Kelley | ||
| 3 | * | ||
| 4 | * This file is part of zig, which is MIT licensed. | ||
| 5 | * See http://opensource.org/licenses/MIT | ||
| 6 | */ | ||
| 7 | |||
| 1 | #ifndef ZIG_TOKENIZER_HPP | 8 | #ifndef ZIG_TOKENIZER_HPP |
| 2 | #define ZIG_TOKENIZER_HPP | 9 | #define ZIG_TOKENIZER_HPP |
| 3 | 10 |
test/hello.zig+1-3| ... | @@ -1,6 +1,4 @@ | ... | @@ -1,6 +1,4 @@ |
| 1 | 1 | fn main(argc: i32, argv: *mut u8) -> i32 { | |
| 2 | |||
| 3 | fn main(argc: isize, argv: *mut u8) -> isize { | ||
| 4 | puts("Hello, world!\n"); | 2 | puts("Hello, world!\n"); |
| 5 | return 0; | 3 | return 0; |
| 6 | } | 4 | } |