diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 2096376..edc62f9 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -3,8 +3,8 @@ { "name": "Linux", "compilerPath": "/usr/bin/clang", - "cStandard": "c99", - "cppStandard": "c++99", + "cStandard": "C23", + "cppStandard": "c++23", "intelliSenseMode": "linux-clang-x64", "includePath": [ "${workspaceFolder}/**" diff --git a/src/lexer/lex.l b/src/lexer/lex.l index 91ee032..c10b76c 100644 --- a/src/lexer/lex.l +++ b/src/lexer/lex.l @@ -7,26 +7,26 @@ #define GET_STATE LexerState *state = (LexerState *)yyget_extra(yyscanner); #define COLUMN_NO state->current_column -int yywrap(void *) { +int yywrap(void * unused_param) { + (void)unused_param; return 1; } %} %% -"." { return TOKEN_DOT; } -"," {return TOKEN_COMMA; } -":" {return TOKEN_COLON; } - +"." { return TOKEN_DOT; } +"," { return TOKEN_COMMA; } +":" { return TOKEN_COLON; } "=" { return TOKEN_ASSIGN; } -"+=" { return TOKEN_ASSIGN_PLUS; } -"-=" { return TOKEN_ASSIGN_MINUS; } -"//=" { return TOKEN_ASSIGN_FLOORDIV; } -"/=" { return TOKEN_ASSIGN_SLASH; } -"%=" { return TOKEN_ASSIGN_MODULO; } -"*=" { return TOKEN_ASSIGN_STAR; } -"^=" { return TOKEN_ASSIGN_CARET; } +"+=" { return TOKEN_ASSIGN_PLUS; } +"-=" { return TOKEN_ASSIGN_MINUS; } +"//=" { return TOKEN_ASSIGN_FLOORDIV; } +"/=" { return TOKEN_ASSIGN_SLASH; } +"%=" { return TOKEN_ASSIGN_MODULO; } +"*=" { return TOKEN_ASSIGN_STAR; } +"^=" { return TOKEN_ASSIGN_CARET; } "not"[ \t]+"in" { return TOKEN_NOT_IN; } "&&" { return TOKEN_AND; } @@ -47,7 +47,7 @@ int yywrap(void *) { "if" { return TOKEN_IF; } -"else if" { return TOKEN_ELSE_IF; } +"else"[ \t]+"if" { return TOKEN_ELSE_IF; } "else" { return TOKEN_ELSE; } "while" { return TOKEN_WHILE; } "forever" { return TOKEN_FOREVER; } diff --git a/src/parser/assignable/access/access.c b/src/parser/assignable/access/access.c new file mode 100644 index 0000000..cd2e54d --- /dev/null +++ b/src/parser/assignable/access/access.c @@ -0,0 +1,28 @@ +#include "access.h" +#include "../../../lexer/token.h" +#include "../../parser.h" +#include +#include +#include "../../../memory.h" + +ParsedValue *parse_access(char*file,DArray *tokens, size_t * index, ParsedValue * to_access) { + (*index)++; + error_if_finished(file, tokens, index); + Token * token = darray_get(tokens, *index); + ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); + ParsedAccess *parsedAccess = checked_malloc(sizeof(ParsedAccess)); + parsedAccess->to_access = to_access; + parsedAccess->access = strcpy(checked_malloc(sizeof(token->value)), token->value); + parsedValue->type = AST_ACCESS; + parsedValue->data = parsedAccess; + return parsedValue; +} + +void free_parse_access(void *ptr) { + ParsedValue *parsedValue = ptr; + ParsedAccess *parsedAccess = parsedValue->data; + free_parsed(parsedAccess->to_access); + free(parsedAccess->access); + free(parsedAccess->to_access); + free(parsedAccess); +} \ No newline at end of file diff --git a/src/parser/assignable/access/access.h b/src/parser/assignable/access/access.h new file mode 100644 index 0000000..36a9b42 --- /dev/null +++ b/src/parser/assignable/access/access.h @@ -0,0 +1,16 @@ +#ifndef ACCESS_H +#define ACCESS_H +#include "../../parser.h" +#include "../../../lexer/token.h" // for Token + +typedef struct { + ParsedValue * to_access; + char * access; +} ParsedAccess; + +// Function declaration for parsing an identifier +ParsedValue *parse_access(char*file,DArray *tokens, size_t * index, ParsedValue * to_access); + +void free_parse_access(void *ptr); + +#endif // ACCESS_H \ No newline at end of file diff --git a/src/parser/assign/assign.c b/src/parser/assignable/assign/assign.c similarity index 71% rename from src/parser/assign/assign.c rename to src/parser/assignable/assign/assign.c index 96d1d36..e3879f8 100644 --- a/src/parser/assign/assign.c +++ b/src/parser/assignable/assign/assign.c @@ -1,21 +1,14 @@ #include "assign.h" -#include "../../lexer/token.h" -#include "../parser.h" +#include "../../../lexer/token.h" +#include "../../parser.h" #include #include #include -#include "../../memory.h" +#include "../../../memory.h" -ParsedValue *parse_assign(char *file, DArray *parsed, DArray *tokens, +ParsedValue *parse_assign(char *file, DArray *tokens, ParsedValue *assign_to, size_t *index) { - bool islet = false; Token *token = darray_get(tokens, *index); - if (token->type == TOKEN_LET) { - islet = true; - (*index)++; - error_if_finished(file,tokens,index); - token = darray_get(tokens, *index); - } switch (assign_to->type) { case AST_IDENTIFIER: case AST_ASSIGN: @@ -31,8 +24,7 @@ ParsedValue *parse_assign(char *file, DArray *parsed, DArray *tokens, (*index)++; error_if_finished(file,tokens,index); token = darray_get(tokens, *index); - assign->from = parse_token(file, parsed, tokens, index, true); - assign->let = islet; + assign->from = parse_token(file, tokens, index, true); ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); parsedValue->type = AST_ASSIGN; parsedValue->data = assign; diff --git a/src/parser/assign/assign.h b/src/parser/assignable/assign/assign.h similarity index 65% rename from src/parser/assign/assign.h rename to src/parser/assignable/assign/assign.h index 3e006b9..57c7e9f 100644 --- a/src/parser/assign/assign.h +++ b/src/parser/assignable/assign/assign.h @@ -1,16 +1,15 @@ #ifndef ASSIGN_H #define ASSIGN_H -#include "../parser.h" -#include "../../lexer/token.h" +#include "../../parser.h" +#include "../../../lexer/token.h" typedef struct { - bool let; ParsedValue * to; TokenType type; ParsedValue * from; } ParsedAssign; -ParsedValue *parse_assign(char*file,DArray *parsed, DArray *tokens, +ParsedValue *parse_assign(char*file, DArray *tokens, ParsedValue *assign_to, size_t *index); void free_parse_assign(void*ptr); diff --git a/src/parser/assignable/call/call.c b/src/parser/assignable/call/call.c new file mode 100644 index 0000000..2a594f0 --- /dev/null +++ b/src/parser/assignable/call/call.c @@ -0,0 +1,59 @@ +#include "call.h" +#include "../../../lexer/token.h" +#include "../../../memory.h" +#include "../../parser.h" +#include +#include +#include + +ParsedValue *parse_call(char *file, DArray *tokens, size_t *index, + ParsedValue *to_call) { + (*index)++; + error_if_finished(file, tokens, index); + ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); + ParsedCall *parsedCall = checked_malloc(sizeof(ParsedCall)); + DArray *args = checked_malloc(sizeof(DArray)); + darray_init(args, sizeof(ParsedValue)); + parsedCall->to_call = to_call; + parsedCall->args = args; + parsedValue->type = AST_ACCESS; + parsedValue->data = parsedCall; + Token *token = darray_get(tokens, *index); + DArray *arg = checked_malloc(sizeof(DArray)); + darray_init(arg, sizeof(ParsedValue)); + while (true) { + bool to_break = false; + switch (token->type) { + case TOKEN_RPAREN: + to_break = true; + break; + default: + break; + } + if (to_break) + break; + ParsedValue *parsedValue = parse_token(file, tokens, index, true); + darray_push(arg, parsedValue); + switch (token->type) { + case TOKEN_COMMA: + darray_push(args, arg); + arg = checked_malloc(sizeof(DArray)); + darray_init(arg, sizeof(ParsedValue)); + break; + default: + break; + } + } + return parsedValue; +} + +void free_parse_call(void *ptr) { + ParsedValue *parsedValue = ptr; + ParsedCall *parsedCall = parsedValue->data; + + free_parsed(parsedCall->to_call); + + + + free(parsedCall); +} \ No newline at end of file diff --git a/src/parser/assignable/call/call.h b/src/parser/assignable/call/call.h new file mode 100644 index 0000000..1b430ae --- /dev/null +++ b/src/parser/assignable/call/call.h @@ -0,0 +1,16 @@ +#ifndef CALL_H +#define CALL_H +#include "../../parser.h" +#include "../../../lexer/token.h" // for Token + +typedef struct { + ParsedValue * to_call; + DArray * args; +} ParsedCall; + +// Function declaration for parsing an identifier +ParsedValue *parse_call(char *file, DArray *tokens, size_t *index, + ParsedValue *to_call); +void free_parse_call(void *ptr); + +#endif // CALL_H \ No newline at end of file diff --git a/src/parser/identifier/identifier.c b/src/parser/assignable/identifier/identifier.c similarity index 77% rename from src/parser/identifier/identifier.c rename to src/parser/assignable/identifier/identifier.c index 075e7d4..28e7864 100644 --- a/src/parser/identifier/identifier.c +++ b/src/parser/assignable/identifier/identifier.c @@ -1,8 +1,8 @@ #include "identifier.h" -#include "../../lexer/token.h" -#include "../parser.h" +#include "../../../lexer/token.h" +#include "../../parser.h" #include -#include "../../memory.h" +#include "../../../memory.h" ParsedValue *parse_identifier(Token *token) { ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue)); diff --git a/src/parser/identifier/identifier.h b/src/parser/assignable/identifier/identifier.h similarity index 70% rename from src/parser/identifier/identifier.h rename to src/parser/assignable/identifier/identifier.h index dccb06a..ea03d2f 100644 --- a/src/parser/identifier/identifier.h +++ b/src/parser/assignable/identifier/identifier.h @@ -2,8 +2,8 @@ #ifndef IDENTIFIER_H #define IDENTIFIER_H -#include "../parser.h" -#include "../../lexer/token.h" // for Token +#include "../../parser.h" +#include "../../../lexer/token.h" // for Token // Function declaration for parsing an identifier ParsedValue * parse_identifier(Token * token); diff --git a/src/parser/declaration/declaration.c b/src/parser/declaration/declaration.c new file mode 100644 index 0000000..8e542ad --- /dev/null +++ b/src/parser/declaration/declaration.c @@ -0,0 +1,30 @@ +#include "declaration.h" +#include "../../lexer/token.h" +#include "../../memory.h" +#include "../parser.h" +#include +#include +#include + +ParsedValue *parse_declaration(char *file, DArray *parsed, DArray *tokens, + size_t *index) { + (*index)++; + error_if_finished(file, tokens, index); + Token *token = darray_get(tokens, *index); + + ParsedValue * parsedValue = malloc(sizeof(ParsedValue)); + ParsedDeclaration * declaration = malloc(sizeof(ParsedDeclaration)); + parsedValue->data = declaration; + parsedValue->type = AST_DECLARATION; + + if (token->type != TOKEN_IDENTIFIER) { + fprintf(stderr, "%s:%u:%u error: declaration requires an identifier\n", + file, token->line, token->column); + exit(EXIT_FAILURE); + } + declaration->name = strcpy(checked_malloc(sizeof(token->value)), token->value); + (*index)++; + if ((*index) >= tokens->size) return parsedValue; + token = darray_get(tokens, *index); + return parsedValue; +} \ No newline at end of file diff --git a/src/parser/declaration/declaration.h b/src/parser/declaration/declaration.h new file mode 100644 index 0000000..6e9376d --- /dev/null +++ b/src/parser/declaration/declaration.h @@ -0,0 +1,16 @@ +#ifndef DECLARATION_H +#define DECLARATION_H +#include "../parser.h" +#include "../../lexer/token.h" // for Token + +typedef struct { + char * name; + bool is_function; + DArray args; // string[] + ParsedValue * from; +} ParsedDeclaration; + +// Function declaration for parsing an identifier +ParsedValue *parse_declaration(char *file, DArray *parsed, DArray *tokens, size_t *index); + +#endif // DECLARATION_H \ No newline at end of file diff --git a/src/parser/if/if.c b/src/parser/if/if.c index ea0a5ef..9bdca56 100644 --- a/src/parser/if/if.c +++ b/src/parser/if/if.c @@ -6,7 +6,7 @@ #include #include "../../memory.h" -ParsedValue *parse_if(char *file, DArray *parsed, DArray *tokens, +ParsedValue *parse_if(char *file, DArray *tokens, size_t *index) { (*index)++; error_if_finished(file, tokens, index); @@ -54,7 +54,7 @@ ParsedValue *parse_if(char *file, DArray *parsed, DArray *tokens, darray_init(condition, sizeof(ParsedValue)); while (*index < tokens->size) { - ParsedValue *parsed_code = parse_token(file, parsed, tokens, index, true); + ParsedValue *parsed_code = parse_token(file, tokens, index, true); if (parsed_code) { darray_push(condition, parsed_code); free(parsed_code); @@ -78,7 +78,7 @@ ParsedValue *parse_if(char *file, DArray *parsed, DArray *tokens, // Parse the body ParsedValue *parsed_content = - parse_token(file, parsed, tokens, index, false); + parse_token(file, tokens, index, false); if (!parsed_content) { fprintf(stderr, @@ -120,6 +120,7 @@ void free_conditional(void *ptr) { if (conditional->condition) darray_free(conditional->condition, free_parsed); free_parsed(conditional->content); + free(conditional->content); } void free_parsed_if(void *ptr) { diff --git a/src/parser/if/if.h b/src/parser/if/if.h index 22d19c3..c8ebedc 100644 --- a/src/parser/if/if.h +++ b/src/parser/if/if.h @@ -10,7 +10,7 @@ typedef struct { ParsedValue *content; } ParsedConditional; -ParsedValue *parse_if(char *file, DArray *parsed, DArray *tokens, +ParsedValue *parse_if(char *file, DArray *tokens, size_t *index); void free_parsed_if(void *ptr); diff --git a/src/parser/parser.c b/src/parser/parser.c index ecf3f4a..7e838f0 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -1,8 +1,8 @@ #include "parser.h" #include "../dynamic_array/darray.h" #include "../lexer/token.h" -#include "assign/assign.h" -#include "identifier/identifier.h" +#include "assignable/assign/assign.h" +#include "assignable/identifier/identifier.h" #include "if/if.h" #include "number/number.h" #include "string/string.h" @@ -12,8 +12,9 @@ #include #include -const char *ValueTypeNames[] = {"string", "assign", "identifier", "number", - "if statement"}; +const char *ValueTypeNames[] = {"string", "assign", "identifier", + "number", "if statement", "access", + "call"}; void error_if_finished(char *file, DArray *tokens, size_t *index) { if ((*index) >= tokens->size) { @@ -24,13 +25,16 @@ void error_if_finished(char *file, DArray *tokens, size_t *index) { } } -ParsedValue *parse_token(char *file, DArray *parsed, DArray *tokens, +ParsedValue *parse_token(char *file, DArray *tokens, size_t *index, bool inline_flag) { Token *token = darray_get(tokens, *index); + + ParsedValue * output = NULL; + if (!inline_flag) { switch (token->type) { case TOKEN_IF: - return parse_if(file, parsed, tokens, index); + return parse_if(file, tokens, index); default: break; }; @@ -38,24 +42,37 @@ ParsedValue *parse_token(char *file, DArray *parsed, DArray *tokens, switch (token->type) { case TOKEN_STRING: (*index)++; - return parse_string(*token); + output = parse_string(*token); + break; case TOKEN_NEW_LINE: while (token->type == TOKEN_NEW_LINE && ++(*index) < tokens->size) { token = darray_get(tokens, *index); } if (token->type == TOKEN_NEW_LINE) - return NULL; - return parse_token(file, parsed, tokens, index, inline_flag); + break; + output = parse_token(file, tokens, index, inline_flag); + break; case TOKEN_INDENT: fprintf(stderr, "%s:%u:%u error: invalid indentation\n", file, token->line, token->column); exit(EXIT_FAILURE); - case TOKEN_LET: - case TOKEN_IDENTIFIER:; - ParsedValue *assign_to = parse_identifier(token); + case TOKEN_IDENTIFIER: (*index)++; - if (*index >= tokens->size) - return assign_to; + output = parse_identifier(token); + break; + case TOKEN_NUMBER: + (*index)++; + output = parse_number(token); + break; + default: + fprintf(stderr, "%s:%u:%u error: syntax error\n", file, token->line, + token->column); + exit(EXIT_FAILURE); + } + + // LHS required + bool passed = false; + while (!passed && (*index) < tokens->size) { token = darray_get(tokens, *index); switch (token->type) { case TOKEN_ASSIGN: @@ -66,43 +83,21 @@ ParsedValue *parse_token(char *file, DArray *parsed, DArray *tokens, case TOKEN_ASSIGN_PLUS: case TOKEN_ASSIGN_SLASH: case TOKEN_ASSIGN_STAR:; - DArray slice = darray_slice(parsed, parsed->size, parsed->size); - return parse_assign(file, &slice, tokens, assign_to, index); - default: - return assign_to; + output = parse_assign(file, tokens, output, index); + break; + default: + passed = true; } - case TOKEN_ASSIGN: - case TOKEN_ASSIGN_CARET: - case TOKEN_ASSIGN_FLOORDIV: - case TOKEN_ASSIGN_MINUS: - case TOKEN_ASSIGN_MODULO: - case TOKEN_ASSIGN_PLUS: - case TOKEN_ASSIGN_SLASH: - case TOKEN_ASSIGN_STAR: - if (parsed->size == 0) { - fprintf(stderr, "%s:%u:%u error: syntax error\n", file, token->line, - token->column); - exit(EXIT_FAILURE); - } - ParsedValue *assigning_to = darray_get(parsed, parsed->size - 1); - fprintf(stderr, "%s:%u:%u error: cannot assign to %s\n", file, token->line, - token->column, ValueTypeNames[assigning_to->type]); - exit(EXIT_FAILURE); - case TOKEN_NUMBER: - (*index)++; - return parse_number(token); - default: - fprintf(stderr, "%s:%u:%u error: syntax error\n", file, token->line, - token->column); - exit(EXIT_FAILURE); } + + return output; } void parser(char *file, DArray *parsed, DArray *tokens, bool inline_flag) { size_t index = 0; while (index < tokens->size) { ParsedValue *parsed_code = - parse_token(file, parsed, tokens, &index, inline_flag); + parse_token(file, tokens, &index, inline_flag); if (parsed_code) { darray_push(parsed, parsed_code); free(parsed_code); diff --git a/src/parser/parser.h b/src/parser/parser.h index 178ba9e..562a06e 100644 --- a/src/parser/parser.h +++ b/src/parser/parser.h @@ -13,6 +13,9 @@ typedef enum { AST_IDENTIFIER, AST_NUMBER, AST_IF, + AST_ACCESS, + AST_CALL, + AST_DECLARATION } ValueType; extern const char* ValueTypeNames[]; @@ -24,7 +27,7 @@ typedef struct { void parser(char *file, DArray *parsed, DArray *tokens, bool inline_flag); -ParsedValue *parse_token(char *file, DArray *parsed, DArray *tokens, +ParsedValue *parse_token(char *file, DArray *tokens, size_t *index, bool inline_flag); void free_parsed(void *ptr); diff --git a/test.ar b/test.ar index a2517d9..1b7fa96 100644 --- a/test.ar +++ b/test.ar @@ -1,2 +1,4 @@ -let x = 10 # hello world -if (x = 10) "hello world" \ No newline at end of file +let y = 0 +let x = 10 + +if (y) x += 1 \ No newline at end of file