From de86179798fe6d84c8ada1f1414f4def1ba52c3a Mon Sep 17 00:00:00 2001 From: Kimplul Date: Mon, 8 May 2023 22:22:58 +0300 Subject: low hanging documentation --- docs/doxygen.conf | 2 +- gen/gen_lexer.c | 198 ++++++++++++++++++++++++------------------------- include/ek/actualize.h | 5 +- include/ek/compiler.h | 18 +++++ include/ek/debug.h | 92 ++++++++++++++++++++++- include/ek/imports.h | 16 +++- include/ek/path.h | 21 ++++++ include/ek/string.h | 75 +++++++++++++++++++ src/compiler.c | 26 ++++++- src/debug.c | 39 +++++++++- src/lexer.l | 4 +- src/parser_helper.c | 1 - 12 files changed, 382 insertions(+), 115 deletions(-) diff --git a/docs/doxygen.conf b/docs/doxygen.conf index 94a6e76..bf142c9 100644 --- a/docs/doxygen.conf +++ b/docs/doxygen.conf @@ -41,7 +41,7 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -PROJECT_NAME = ct +PROJECT_NAME = ek # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version diff --git a/gen/gen_lexer.c b/gen/gen_lexer.c index 14d7899..1484b6b 100644 --- a/gen/gen_lexer.c +++ b/gen/gen_lexer.c @@ -602,11 +602,12 @@ static const flex_int16_t yy_chk[433] = static void update_yylloc(struct parser *parser, YYLTYPE *lloc, const char *text) { + (void)parser; + lloc->first_line = lloc->last_line; lloc->first_column = lloc->last_column; for (size_t i = 0; text[i] != 0; ++i) { - parser->buf_offset++; if (text[i] == '\n') { lloc->last_line++; /* flex uses 1 based indexing */ @@ -618,9 +619,9 @@ static void update_yylloc(struct parser *parser, YYLTYPE *lloc, const char *text } #define YY_USER_ACTION update_yylloc(parser, yylloc, yytext); -#line 622 "gen/gen_lexer.c" +#line 623 "gen/gen_lexer.c" -#line 624 "gen/gen_lexer.c" +#line 625 "gen/gen_lexer.c" #define INITIAL 0 #define SC_COMMENT 1 @@ -879,9 +880,9 @@ YY_DECL } { -#line 47 "src/lexer.l" +#line 48 "src/lexer.l" -#line 885 "gen/gen_lexer.c" +#line 886 "gen/gen_lexer.c" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { @@ -940,23 +941,23 @@ do_action: /* This label is used only to access EOF actions. */ case 1: YY_RULE_SETUP -#line 48 "src/lexer.l" +#line 49 "src/lexer.l" {/* skip line comments */} YY_BREAK case 2: YY_RULE_SETUP -#line 50 "src/lexer.l" +#line 51 "src/lexer.l" {BEGIN(SC_COMMENT);} YY_BREAK case 3: YY_RULE_SETUP -#line 52 "src/lexer.l" +#line 53 "src/lexer.l" {++parser->comment_nesting;} YY_BREAK case 4: YY_RULE_SETUP -#line 53 "src/lexer.l" +#line 54 "src/lexer.l" { if (parser->comment_nesting) --parser->comment_nesting; @@ -966,135 +967,135 @@ YY_RULE_SETUP YY_BREAK case 5: YY_RULE_SETUP -#line 60 "src/lexer.l" +#line 61 "src/lexer.l" {} YY_BREAK case 6: YY_RULE_SETUP -#line 61 "src/lexer.l" +#line 62 "src/lexer.l" {} YY_BREAK case 7: YY_RULE_SETUP -#line 62 "src/lexer.l" +#line 63 "src/lexer.l" {} YY_BREAK case 8: /* rule 8 can match eol */ YY_RULE_SETUP -#line 63 "src/lexer.l" +#line 64 "src/lexer.l" {} YY_BREAK case 9: YY_RULE_SETUP -#line 66 "src/lexer.l" +#line 67 "src/lexer.l" {return SCOPE;} YY_BREAK case 10: YY_RULE_SETUP -#line 67 "src/lexer.l" +#line 68 "src/lexer.l" {return LPAREN;} YY_BREAK case 11: YY_RULE_SETUP -#line 68 "src/lexer.l" +#line 69 "src/lexer.l" {return RPAREN;} YY_BREAK case 12: YY_RULE_SETUP -#line 69 "src/lexer.l" +#line 70 "src/lexer.l" {return LBRACE;} YY_BREAK case 13: YY_RULE_SETUP -#line 70 "src/lexer.l" +#line 71 "src/lexer.l" {return RBRACE;} YY_BREAK case 14: YY_RULE_SETUP -#line 71 "src/lexer.l" +#line 72 "src/lexer.l" {return LBRACKET;} YY_BREAK case 15: YY_RULE_SETUP -#line 72 "src/lexer.l" +#line 73 "src/lexer.l" {return RBRACKET;} YY_BREAK case 16: YY_RULE_SETUP -#line 73 "src/lexer.l" +#line 74 "src/lexer.l" {return DOT;} YY_BREAK case 17: YY_RULE_SETUP -#line 74 "src/lexer.l" +#line 75 "src/lexer.l" {return COMMA;} YY_BREAK case 18: YY_RULE_SETUP -#line 75 "src/lexer.l" +#line 76 "src/lexer.l" {return SEMICOLON;} YY_BREAK case 19: YY_RULE_SETUP -#line 76 "src/lexer.l" +#line 77 "src/lexer.l" {return COLON;} YY_BREAK case 20: YY_RULE_SETUP -#line 77 "src/lexer.l" +#line 78 "src/lexer.l" {return BANG;} YY_BREAK case 21: YY_RULE_SETUP -#line 78 "src/lexer.l" +#line 79 "src/lexer.l" {return PASTE;} YY_BREAK case 22: YY_RULE_SETUP -#line 79 "src/lexer.l" +#line 80 "src/lexer.l" {return AT;} YY_BREAK case 23: YY_RULE_SETUP -#line 81 "src/lexer.l" +#line 82 "src/lexer.l" {return PLUS;} YY_BREAK case 24: YY_RULE_SETUP -#line 82 "src/lexer.l" +#line 83 "src/lexer.l" {return MINUS;} YY_BREAK case 25: YY_RULE_SETUP -#line 83 "src/lexer.l" +#line 84 "src/lexer.l" {return STAR;} YY_BREAK case 26: YY_RULE_SETUP -#line 84 "src/lexer.l" +#line 85 "src/lexer.l" {return DIV;} YY_BREAK case 27: YY_RULE_SETUP -#line 85 "src/lexer.l" +#line 86 "src/lexer.l" {return REM;} YY_BREAK case 28: YY_RULE_SETUP -#line 86 "src/lexer.l" +#line 87 "src/lexer.l" {return XOR;} YY_BREAK case 29: YY_RULE_SETUP -#line 87 "src/lexer.l" +#line 88 "src/lexer.l" {return POW;} YY_BREAK case 30: /* rule 30 can match eol */ YY_RULE_SETUP -#line 89 "src/lexer.l" +#line 90 "src/lexer.l" { /* regular character constant, 'a' */ yylval->integer = yytext[1]; @@ -1103,7 +1104,7 @@ YY_RULE_SETUP YY_BREAK case 31: YY_RULE_SETUP -#line 95 "src/lexer.l" +#line 96 "src/lexer.l" { /* hex character constant, '\xef' */ /* handling is slightly different from C, here it's more or less just @@ -1114,7 +1115,7 @@ YY_RULE_SETUP YY_BREAK case 32: YY_RULE_SETUP -#line 103 "src/lexer.l" +#line 104 "src/lexer.l" { /* octal character constant, '\033' */ yylval->integer = strtoll(yytext + 2, NULL, 8); @@ -1123,7 +1124,7 @@ YY_RULE_SETUP YY_BREAK case 33: YY_RULE_SETUP -#line 109 "src/lexer.l" +#line 110 "src/lexer.l" { /* binary character constant, '\b101' */ yylval->integer = strtoll(yytext + 3, NULL, 2); @@ -1132,7 +1133,7 @@ YY_RULE_SETUP YY_BREAK case 34: YY_RULE_SETUP -#line 115 "src/lexer.l" +#line 116 "src/lexer.l" { /* escaped character constant */ yylval->integer = match_escape(yytext[2]); @@ -1141,273 +1142,273 @@ YY_RULE_SETUP YY_BREAK case 35: YY_RULE_SETUP -#line 121 "src/lexer.l" +#line 122 "src/lexer.l" {return SQUOTE;} YY_BREAK case 36: YY_RULE_SETUP -#line 123 "src/lexer.l" +#line 124 "src/lexer.l" {return AND;} YY_BREAK case 37: YY_RULE_SETUP -#line 124 "src/lexer.l" +#line 125 "src/lexer.l" {return LAND;} YY_BREAK case 38: YY_RULE_SETUP -#line 125 "src/lexer.l" +#line 126 "src/lexer.l" {return OR;} YY_BREAK case 39: YY_RULE_SETUP -#line 126 "src/lexer.l" +#line 127 "src/lexer.l" {return LOR;} YY_BREAK case 40: YY_RULE_SETUP -#line 128 "src/lexer.l" +#line 129 "src/lexer.l" {return TILDE;} YY_BREAK case 41: YY_RULE_SETUP -#line 129 "src/lexer.l" +#line 130 "src/lexer.l" {return TO;} YY_BREAK case 42: YY_RULE_SETUP -#line 130 "src/lexer.l" +#line 131 "src/lexer.l" {return LT;} YY_BREAK case 43: YY_RULE_SETUP -#line 131 "src/lexer.l" +#line 132 "src/lexer.l" {return GT;} YY_BREAK case 44: YY_RULE_SETUP -#line 132 "src/lexer.l" +#line 133 "src/lexer.l" {return LE;} YY_BREAK case 45: YY_RULE_SETUP -#line 133 "src/lexer.l" +#line 134 "src/lexer.l" {return GE;} YY_BREAK case 46: YY_RULE_SETUP -#line 134 "src/lexer.l" +#line 135 "src/lexer.l" {return NE;} YY_BREAK case 47: YY_RULE_SETUP -#line 135 "src/lexer.l" +#line 136 "src/lexer.l" {return EQ;} YY_BREAK case 48: YY_RULE_SETUP -#line 137 "src/lexer.l" +#line 138 "src/lexer.l" {return FATARROW;} YY_BREAK case 49: YY_RULE_SETUP -#line 139 "src/lexer.l" +#line 140 "src/lexer.l" {return LSHIFT;} YY_BREAK case 50: YY_RULE_SETUP -#line 140 "src/lexer.l" +#line 141 "src/lexer.l" {return RSHIFT;} YY_BREAK case 51: YY_RULE_SETUP -#line 142 "src/lexer.l" +#line 143 "src/lexer.l" {return PLUSSELF;} YY_BREAK case 52: YY_RULE_SETUP -#line 143 "src/lexer.l" +#line 144 "src/lexer.l" {return MINUSSELF;} YY_BREAK case 53: YY_RULE_SETUP -#line 144 "src/lexer.l" +#line 145 "src/lexer.l" {return DIVSELF;} YY_BREAK case 54: YY_RULE_SETUP -#line 145 "src/lexer.l" +#line 146 "src/lexer.l" {return REMSELF;} YY_BREAK case 55: YY_RULE_SETUP -#line 146 "src/lexer.l" +#line 147 "src/lexer.l" {return XORSELF;} YY_BREAK case 56: YY_RULE_SETUP -#line 147 "src/lexer.l" +#line 148 "src/lexer.l" {return POWSELF;} YY_BREAK case 57: YY_RULE_SETUP -#line 148 "src/lexer.l" +#line 149 "src/lexer.l" {return ORSELF;} YY_BREAK case 58: YY_RULE_SETUP -#line 149 "src/lexer.l" +#line 150 "src/lexer.l" {return ORSELF;} YY_BREAK case 59: YY_RULE_SETUP -#line 150 "src/lexer.l" +#line 151 "src/lexer.l" {return LSHIFTSELF;} YY_BREAK case 60: YY_RULE_SETUP -#line 151 "src/lexer.l" +#line 152 "src/lexer.l" {return RSHIFTSELF;} YY_BREAK case 61: YY_RULE_SETUP -#line 152 "src/lexer.l" +#line 153 "src/lexer.l" {return ELLIPSIS;} YY_BREAK case 62: YY_RULE_SETUP -#line 154 "src/lexer.l" +#line 155 "src/lexer.l" {return AS;} YY_BREAK case 63: YY_RULE_SETUP -#line 155 "src/lexer.l" +#line 156 "src/lexer.l" {return PUB;} YY_BREAK case 64: YY_RULE_SETUP -#line 156 "src/lexer.l" +#line 157 "src/lexer.l" {return DEFER;} YY_BREAK case 65: YY_RULE_SETUP -#line 157 "src/lexer.l" +#line 158 "src/lexer.l" {return UNION;} YY_BREAK case 66: YY_RULE_SETUP -#line 158 "src/lexer.l" +#line 159 "src/lexer.l" {return STRUCT;} YY_BREAK case 67: YY_RULE_SETUP -#line 159 "src/lexer.l" +#line 160 "src/lexer.l" {return TYPEDEF;} YY_BREAK case 68: YY_RULE_SETUP -#line 160 "src/lexer.l" +#line 161 "src/lexer.l" {return IMPORT;} YY_BREAK case 69: YY_RULE_SETUP -#line 161 "src/lexer.l" +#line 162 "src/lexer.l" {return TYPEOF;} YY_BREAK case 70: YY_RULE_SETUP -#line 162 "src/lexer.l" +#line 163 "src/lexer.l" {return SIZEOF;} YY_BREAK case 71: YY_RULE_SETUP -#line 163 "src/lexer.l" +#line 164 "src/lexer.l" {return EMBED;} YY_BREAK case 72: YY_RULE_SETUP -#line 164 "src/lexer.l" +#line 165 "src/lexer.l" {return IF;} YY_BREAK case 73: YY_RULE_SETUP -#line 165 "src/lexer.l" +#line 166 "src/lexer.l" {return GOTO;} YY_BREAK case 74: YY_RULE_SETUP -#line 166 "src/lexer.l" +#line 167 "src/lexer.l" {return ELSE;} YY_BREAK case 75: YY_RULE_SETUP -#line 167 "src/lexer.l" +#line 168 "src/lexer.l" {return SWITCH;} YY_BREAK case 76: YY_RULE_SETUP -#line 168 "src/lexer.l" +#line 169 "src/lexer.l" {return CASE;} YY_BREAK case 77: YY_RULE_SETUP -#line 169 "src/lexer.l" +#line 170 "src/lexer.l" {return FOR;} YY_BREAK case 78: YY_RULE_SETUP -#line 170 "src/lexer.l" +#line 171 "src/lexer.l" {return WHILE;} YY_BREAK case 79: YY_RULE_SETUP -#line 171 "src/lexer.l" +#line 172 "src/lexer.l" {return DO;} YY_BREAK case 80: YY_RULE_SETUP -#line 172 "src/lexer.l" +#line 173 "src/lexer.l" {return MUT;} YY_BREAK case 81: YY_RULE_SETUP -#line 173 "src/lexer.l" +#line 174 "src/lexer.l" {return CONST;} YY_BREAK case 82: YY_RULE_SETUP -#line 174 "src/lexer.l" +#line 175 "src/lexer.l" {return RETURN;} YY_BREAK case 83: YY_RULE_SETUP -#line 175 "src/lexer.l" +#line 176 "src/lexer.l" {return EXTERN;} YY_BREAK case 84: YY_RULE_SETUP -#line 176 "src/lexer.l" +#line 177 "src/lexer.l" {return ENUM;} YY_BREAK case 85: YY_RULE_SETUP -#line 177 "src/lexer.l" +#line 178 "src/lexer.l" {return DEFINE;} YY_BREAK case 86: YY_RULE_SETUP -#line 178 "src/lexer.l" +#line 179 "src/lexer.l" {return BREAK;} YY_BREAK case 87: YY_RULE_SETUP -#line 179 "src/lexer.l" +#line 180 "src/lexer.l" {return CONTINUE;} YY_BREAK case 88: /* rule 88 can match eol */ YY_RULE_SETUP -#line 181 "src/lexer.l" +#line 182 "src/lexer.l" { /* seems risky, I know, but letting the parser choose when to allocate a * new string seems to help with syntax error cleanup */ @@ -1417,7 +1418,7 @@ YY_RULE_SETUP YY_BREAK case 89: YY_RULE_SETUP -#line 188 "src/lexer.l" +#line 189 "src/lexer.l" { yylval->integer = strtoll(yytext, 0, 0); return INT; @@ -1425,7 +1426,7 @@ YY_RULE_SETUP YY_BREAK case 90: YY_RULE_SETUP -#line 193 "src/lexer.l" +#line 194 "src/lexer.l" { yylval->dbl = strtod(yytext, 0); return FLOAT; @@ -1433,7 +1434,7 @@ YY_RULE_SETUP YY_BREAK case 91: YY_RULE_SETUP -#line 198 "src/lexer.l" +#line 199 "src/lexer.l" { yylval->str = yytext; return ID; @@ -1442,19 +1443,18 @@ YY_RULE_SETUP case 92: /* rule 92 can match eol */ YY_RULE_SETUP -#line 204 "src/lexer.l" +#line 205 "src/lexer.l" {/* skip whitespace */} YY_BREAK case 93: YY_RULE_SETUP -#line 206 "src/lexer.l" +#line 207 "src/lexer.l" { struct src_issue issue; issue.level = SRC_ERROR; issue.loc = to_src_loc(yylloc); issue.fctx.fbuf = parser->buf; issue.fctx.fname = parser->fname; - issue.offset = parser->buf_offset; src_issue(issue, "Unexpected token: %s", yytext); parser->failed = true; } diff --git a/include/ek/actualize.h b/include/ek/actualize.h index 18755b1..9cee764 100644 --- a/include/ek/actualize.h +++ b/include/ek/actualize.h @@ -7,9 +7,8 @@ /** * @file actualize.h * - * Actualization stuff, that is stuff needed for turning raw AST - * into processed AST that can be passed to a backend to generate - * code. + * Actualization stuff needed for turning raw AST + * into processed AST that can be passed to a backend to generate code. */ #include diff --git a/include/ek/compiler.h b/include/ek/compiler.h index 8e3d221..32fc218 100644 --- a/include/ek/compiler.h +++ b/include/ek/compiler.h @@ -12,7 +12,25 @@ #include +/** + * Compile a root file. + * A root file is a file given on the command line, and is assumed to + * create a file tree that eventually results in a binary. + * + * @param file Root file to compile. + * @return \c 0 if compilation was succesful, otherwise some non-zero value. + */ int compile(const char *file); + +/** + * Process a file, i.e. lex, parse and generate raw AST. + * + * @param parent Parent scope of file from which \p file is imported. + * \c NULL if root file. + * @param public \c 1 if \p file should be publicly imported, \c 0 otherwise. + * @param file File to process. + * @return \c 0 if compilation was succesful, otherwise some non-zero value. + */ int process_file(struct scope **parent, int public, const char *file); #endif /* EK_COMPILER_H */ diff --git a/include/ek/debug.h b/include/ek/debug.h index 7dca003..d222cf4 100644 --- a/include/ek/debug.h +++ b/include/ek/debug.h @@ -15,49 +15,139 @@ #include #if DEBUG +/** + * Print debugging message. Only active if \c DEBUG is defined, + * + * @param x Format string. Follows standard printf() formatting. + */ #define debug(x, ...) \ do {fprintf(stderr, "debug: " x "\n",##__VA_ARGS__);} while(0) #else #define debug(x, ...) #endif +/** + * Print error message. + * + * @param x Format string. Follows standard printf() formatting. + */ #define error(x, ...) \ do {fprintf(stderr, "error: " x "\n",##__VA_ARGS__);} while(0) +/** + * Print warning message. + * + * @param x Format string. Follows standard printf() formatting. + */ #define warn(x, ...) \ do {fprintf(stderr, "warn: " x "\n",##__VA_ARGS__);} while(0) +/** + * Print info message. + * + * @param x Format string. Follows standard printf() formatting. + */ #define info(x, ...) \ do {fprintf(stderr, "info: " x "\n",##__VA_ARGS__);} while(0) +/** Keeps track of file name and file buffer. */ struct file_ctx { + /** File name. */ const char *fname; + /** File buffer. */ const char *fbuf; }; +/** + * Generate string representation of type. + * + * @param type Type to generate string representation of. + * @return \p type as string. + */ char *type_str(struct ast_node *type); + +/** + * Generate string representation of call. + * + * @param call Call to generate string representation of. + * @return \p call as string. + */ char *call_str(struct ast_node *call); + +/** + * Print info that relates to a specific AST node. + * Recommended for situations where it may be useful to clarify some + * previous error or warning. + * + * @param ctx File context \p node was generated from. + * @param node AST node to print message with. + * @param fmt Format string. Follows standard printf() formatting. + */ void semantic_info(struct file_ctx ctx, struct ast_node *node, const char *fmt, ...); + +/** + * Print warning that relates to a specific AST node. + * Recommended for situations where the user wrote some shady code + * and it might be unclear what was meant. + * + * The language itself tries to avoid such situations, and as such warnings + * should probably be avoided in favor of errors. Still, I can imagine that + * there are situations where warnings can be useful, so it's provided. + * + * @param ctx File context \p node was generated from. + * @param node AST node to print message with. + * @param fmt Format string. Follows standard printf() formatting. + */ void semantic_warn(struct file_ctx ctx, struct ast_node *node, const char *fmt, ...); + +/** + * Print warning that relates to a specific AST node. + * Recommended for situations where the user messed up. + * + * @param ctx File context \p node was generated from. + * @param node AST node to print message with. + * @param fmt Format string. Follows standard printf() formatting. + */ void semantic_error(struct file_ctx ctx, struct ast_node *node, const char *fmt, ...); + +/** + * Print internal error. + * Recommended for situations where the developer (probably me) messed up. + * + * @param fmt Format string. Follows standard printf() formatting. + */ void internal_error(const char *fmt, ...); +/** Issue categorization. */ enum issue_level { + /** Information. */ SRC_INFO, + /** Warning. */ SRC_WARN, + /** Error. */ SRC_ERROR }; +/** Context for issue in user code. */ struct src_issue { + /** How bad the issue is. */ enum issue_level level; + /** Where the issue happened relative to file buffer. */ struct src_loc loc; + /** File context issue happened in. */ struct file_ctx fctx; - size_t offset; }; +/** + * Print a source issue. + * + * @param issue Context for issue. + * @param err_msg Format string. Follows standard printf() formatting. + */ void src_issue(struct src_issue issue, const char *err_msg, ...); + #endif /* EK_DEBUG_H */ diff --git a/include/ek/imports.h b/include/ek/imports.h index 801eb06..43603c4 100644 --- a/include/ek/imports.h +++ b/include/ek/imports.h @@ -9,13 +9,25 @@ * * File import handling. * Currently mostly unimplemented, but intended to keep track - * of which files have been imported. + * of where to find files for import. */ #include +/** + * Add import path to search for files in. + * + * @param dir Directory to search files in. Either absolute or relative. + */ void add_import_path(const char *dir); + +/** + * Search for \p file in import path. + * @todo implement. + * + * @param file File name to search for. + * @return Full path to \p file if found, \c NULL otherwise. + */ const char *find_import(const char *file); -bool already_imported(const char *file); #endif /* EK_IMPORTS_H */ diff --git a/include/ek/path.h b/include/ek/path.h index 2ddfb4c..2e15932 100644 --- a/include/ek/path.h +++ b/include/ek/path.h @@ -10,8 +10,29 @@ * Path handling helpers. */ +/** + * Get basename of file path. + * E.g. src/some/file.c -> file.c + * + * @param file File path to get basename from. + * @return Basename of \p file. + */ char *ek_basename(const char *file); + +/** + * Get directory name of path. + * E.g. src/some/file.c -> src/some + * + * @param file File path to get dirname from. + * @return Dirname of \p file. + */ char *ek_dirname(const char *file); + +/** + * Get current working directory. + * + * @return Current working directory. + */ char *ek_cwdname(); #endif /* EK_PATH */ diff --git a/include/ek/string.h b/include/ek/string.h index 5c561a7..bbe8779 100644 --- a/include/ek/string.h +++ b/include/ek/string.h @@ -9,28 +9,103 @@ * * String handling helper stuff. * At the moment mostly unused. + * Doesn't implement short string optimizations or anything like that for now. */ #include #include #include +/** Simple representation of a string. */ struct string { + /** Lenght of string. */ size_t len; + /** String buffer. */ char *buf; }; +/** + * Create new string from null terminated character array. + * Allocates a string object on the heap and copies \p s into it. + * + * @param s Null terminated character array. + * @return \p s as a string. + */ struct string *new_string(const char *s); + +/** + * Destroy previously created string. + * Frees the string and anything associated with it. + * + * @param s String to destroy. + */ void destroy_string(struct string *s); +/** + * Append a character to a string. + * + * @param s String to append \c to. + * @param c Character to append to \p s. + * @return \c 0 if appending succeeded, non-zero otherwise. + */ int str_append(struct string *s, char c); + +/** + * Concatenate a string and a null terminated character array. + * Essentially adds \p c to the end of \p s. + * + * @param s String to concatenate \p c with. + * @param c Null terminated character array to concatenate with \p s. + * @return \c 0 if concatenation succeeded, non-zero otherwise. + */ int str_concat(struct string *s, const char *c); + +/** + * Add \p c to the end of \p s. + * + * @param s String to add \p c to. + * @param c String to att to \p s. + * @return \c 0 if addition succeedes, non-zero otherwise. + */ int str_add(struct string *s, struct string *c); +/** + * Get character at index \p i in \p s. + * + * @todo implement, range checking? + * + * @param s String to index into. + * @param i Index of character to get. + * @return Character at \p i in \p s. + */ char str_index(struct string *s, size_t i); + +/** + * Get character at index \p i from the end of \p s. + * + * @todo implement, range checking? + * + * @param s String to index into? + * @param i Index of character from the end to get. + * @return Character at \p i from the end of \p s. + */ char str_rindex(struct string *s, size_t i); +/** + * Compare string with null-terminated character array. + * Essentially a wrapper around strncmp(). + * + * @param s String to compare against \p c. + * @param c Null-terminated array to compare against \p s. + * @return \c true if identical, \c false otherwise. + */ bool str_compare(struct string *s, const char *c); + +/** + * Clear content of string. + * + * @param s String to clear content of. + */ void str_clear(struct string *s); #endif /* EK_STRING_H */ diff --git a/src/compiler.c b/src/compiler.c index 68414c7..607618e 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -24,10 +24,20 @@ #include #include +/** + * Read whole file into a buffer and return pointer to buffer. + * Possibly kind of silly to have both \p file and \p f. + * Apparently there's no standardized way to get the file name of a + * file pointer. + * + * @param file Name of file to read. + * @param f File pointer. + * @return Pointer to buffer with file contents. + */ static char *read_file(const char *file, FILE *f) { fseek(f, 0, SEEK_END); - /* TODO: check how well standardized this actually is */ + /** @todo check how well standardized this actually is */ long s = ftell(f); if (s == LONG_MAX) { error("%s might be a directory", file); @@ -46,6 +56,16 @@ static char *read_file(const char *file, FILE *f) return buf; } +/** + * Helper for process_file(), actually processes the file + * after process_file() has done path lookups and working directory + * changes and whatnot. + * + * @param parent Parent file context. \c NULL if root file. + * @param public \c 1 if file is being imported publicly, \c 0 otherwise. + * @param file File name to process. + * @return \c 0 if processing was succesful, non-zero value otherwise. + */ static int process(struct scope **parent, int public, const char *file) { FILE *f = fopen(file, "rb"); @@ -99,7 +119,7 @@ static int process(struct scope **parent, int public, const char *file) int process_file(struct scope **scope, int public, const char *file) { int res = -1; - /* TODO: report failure allocating stuff maybe? */ + /** todo report failure allocating stuff maybe? */ struct res *r = res_create(); if (!r) return -1; @@ -153,7 +173,7 @@ int compile(const char *file) { } ret = actualize_main(root); - /* TODO: backend */ + /** @todo backend */ destroy_scope(root); return ret; } diff --git a/src/debug.c b/src/debug.c index 1be19af..017f07f 100644 --- a/src/debug.c +++ b/src/debug.c @@ -16,6 +16,12 @@ #include +/** + * Get string representation of issue_level. + * + * @param level issue_level to get string representation for. + * @return \p level as a string. + */ const char *issue_level_str(enum issue_level level) { switch (level) { @@ -27,9 +33,19 @@ const char *issue_level_str(enum issue_level level) return "unknown"; } +/** + * Find position in file buffer where line number \p no + * starts. Lines are assumed to be one-indexed, with + * \p no = \c 0 and \p no = \c 1 both considered the first line. + * + * @param buf Buffer to look in. + * @param no Line number whose start to look for. + * @return Pointer to location in buffer where line number \p no + * starts. + */ static const char *find_lineno(const char *buf, size_t no) { - if (no == 1) + if (no == 0 || no == 1) return buf; char c; @@ -46,6 +62,13 @@ static const char *find_lineno(const char *buf, size_t no) return buf; } +/** + * Helper for printing out an issue. + * + * @param issue Issue context. + * @param fmt Format string. Follows standard printf() formatting. + * @param args Arguments for \p fmt. + */ static void _issue(struct src_issue issue, const char *fmt, va_list args) { /* get start and end of current line in buffer */ @@ -97,8 +120,6 @@ void src_issue(struct src_issue issue, const char *err_msg, ...) va_end(args); } -/* TODO: should really implement these better, the bad error messages are - * starting to play a role in debugging */ void semantic_error(struct file_ctx fctx, struct ast_node *node, const char *fmt, ...) { @@ -148,6 +169,12 @@ void internal_error(const char *fmt, ...) va_end(args); } +/** + * Workhorse for type_str(). + * + * @param fp File pointer to write string representation to. + * @param type Type to generate string representation for. + */ static void _type_str(FILE *fp, struct ast_node *type) { if (!type) @@ -269,6 +296,12 @@ char *type_str(struct ast_node *node) return buf; } +/** + * Workhorse for call_str(). + * + * @param f File pointer to write string representation to. + * @param call Call to generate string representation for. + */ static void _call_str(FILE *f, struct ast_node *call) { struct ast_node *id = call->_call.id; diff --git a/src/lexer.l b/src/lexer.l index c855287..c30e802 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -9,11 +9,12 @@ static void update_yylloc(struct parser *parser, YYLTYPE *lloc, const char *text) { + (void)parser; + lloc->first_line = lloc->last_line; lloc->first_column = lloc->last_column; for (size_t i = 0; text[i] != 0; ++i) { - parser->buf_offset++; if (text[i] == '\n') { lloc->last_line++; /* flex uses 1 based indexing */ @@ -209,7 +210,6 @@ STRING \"(\\.|[^"\\])*\" issue.loc = to_src_loc(yylloc); issue.fctx.fbuf = parser->buf; issue.fctx.fname = parser->fname; - issue.offset = parser->buf_offset; src_issue(issue, "Unexpected token: %s", yytext); parser->failed = true; } diff --git a/src/parser_helper.c b/src/parser_helper.c index 15dd6e8..5a90df8 100644 --- a/src/parser_helper.c +++ b/src/parser_helper.c @@ -87,7 +87,6 @@ void yyerror(YYLTYPE *yylloc, void *lexer, struct parser *parser, issue.loc = to_src_loc(yylloc); issue.fctx.fbuf = parser->buf; issue.fctx.fname = parser->fname; - issue.offset = parser->buf_offset; src_issue(issue, msg); } -- cgit v1.3