|
|
|
@@ -1,5 +1,13 @@ |
|
|
|
char* parser_file; |
|
|
|
int parser_line; |
|
|
|
int parser_col; |
|
|
|
|
|
|
|
#define inject_scl(_ret) \ |
|
|
|
ret->sourceCodeLocation = new(Source_Code_Location); \ |
|
|
|
ret->sourceCodeLocation->file = parser_file; \ |
|
|
|
ret->sourceCodeLocation->line = parser_line; \ |
|
|
|
ret->sourceCodeLocation->column = parser_col |
|
|
|
|
|
|
|
|
|
|
|
// TODO(Felix): use the array list macro here? |
|
|
|
Ast_Node_Array_List* create_Ast_Node_Array_List(int initial_length) { |
|
|
|
@@ -30,13 +38,10 @@ void eat_comment_line(char* text, int* index_in_text) { |
|
|
|
// eat the comment line |
|
|
|
do { |
|
|
|
++(*index_in_text); |
|
|
|
++parser_col; |
|
|
|
} while (text[(*index_in_text)] != '\n' && |
|
|
|
text[(*index_in_text)] != '\r' && |
|
|
|
text[(*index_in_text)] != '\0'); |
|
|
|
|
|
|
|
if (text[(*index_in_text)] == '\n') { |
|
|
|
++parser_line; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void eat_whitespace(char* text, int* index_in_text) { |
|
|
|
@@ -44,12 +49,16 @@ void eat_whitespace(char* text, int* index_in_text) { |
|
|
|
while (text[(*index_in_text)] == ' ' || |
|
|
|
text[(*index_in_text)] == '\t' || |
|
|
|
text[(*index_in_text)] == '\n' || |
|
|
|
text[(*index_in_text)] == '\r') { |
|
|
|
text[(*index_in_text)] == '\r') |
|
|
|
{ |
|
|
|
if (text[(*index_in_text)] == '\n') { |
|
|
|
++parser_line; |
|
|
|
parser_col = 0; |
|
|
|
} |
|
|
|
++parser_col; |
|
|
|
++(*index_in_text); |
|
|
|
} |
|
|
|
if (text[(*index_in_text)] == '\n') { |
|
|
|
++parser_line; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
void eat_until_code(char* text, int* index_in_text) { |
|
|
|
@@ -98,33 +107,43 @@ Ast_Node* parse_number(char* text, int* index_in_text) { |
|
|
|
double number; |
|
|
|
char* str_number = read_atom(text, index_in_text); |
|
|
|
sscanf(str_number, "%lf", &number); |
|
|
|
return create_ast_node_number(number); |
|
|
|
Ast_Node* ret = create_ast_node_number(number); |
|
|
|
inject_scl(ret); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Ast_Node* parse_keyword(char* text, int* index_in_text) { |
|
|
|
// we are now on the colon |
|
|
|
++(*index_in_text); |
|
|
|
++parser_col; |
|
|
|
char* str_keyword = read_atom(text, index_in_text); |
|
|
|
return create_ast_node_keyword(str_keyword); |
|
|
|
Ast_Node* ret = create_ast_node_keyword(str_keyword); |
|
|
|
inject_scl(ret); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
Ast_Node* parse_symbol(char* text, int* index_in_text) { |
|
|
|
// we are now at the first char of the symbol |
|
|
|
char* str_symbol = read_atom(text, index_in_text); |
|
|
|
return create_ast_node_symbol(str_symbol); |
|
|
|
Ast_Node* ret = create_ast_node_symbol(str_symbol); |
|
|
|
inject_scl(ret); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
Ast_Node* parse_string(char* text, int* index_in_text) { |
|
|
|
// the first character is the '"' |
|
|
|
++(*index_in_text); |
|
|
|
++parser_col; |
|
|
|
|
|
|
|
// now we are at the first letter, if this is the closing '"' then |
|
|
|
// it's easy |
|
|
|
if (text[*index_in_text] == '"') { |
|
|
|
char* str = new(char); |
|
|
|
*str = '\0'; |
|
|
|
return create_ast_node_string(str, 0); |
|
|
|
Ast_Node* ret = create_ast_node_string(str, 0); |
|
|
|
inject_scl(ret); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
// okay so the first letter was not actually closing the string... |
|
|
|
@@ -143,7 +162,7 @@ Ast_Node* parse_string(char* text, int* index_in_text) { |
|
|
|
if (!unescape_string(text+(*index_in_text))) { |
|
|
|
create_error( |
|
|
|
Error_Type_Unknown_Error, |
|
|
|
create_source_code_location(parser_file, parser_line)); |
|
|
|
create_source_code_location(parser_file, parser_line, parser_col)); |
|
|
|
return nullptr; |
|
|
|
} |
|
|
|
strcpy(string, text+(*index_in_text)); |
|
|
|
@@ -159,7 +178,9 @@ Ast_Node* parse_string(char* text, int* index_in_text) { |
|
|
|
*index_in_text += string_length +1; // plus one because we want to |
|
|
|
// go after the quotes |
|
|
|
|
|
|
|
return create_ast_node_string(string, string_length); |
|
|
|
Ast_Node* ret = create_ast_node_string(string, string_length); |
|
|
|
inject_scl(ret); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
Ast_Node* parse_atom(char* text, int* index_in_text) { |
|
|
|
@@ -193,6 +214,7 @@ Ast_Node* parse_atom(char* text, int* index_in_text) { |
|
|
|
Ast_Node* parse_expression(char* text, int* index_in_text) { |
|
|
|
if (text[*index_in_text] == '\'') { |
|
|
|
++(*index_in_text); |
|
|
|
++parser_col; |
|
|
|
Ast_Node* result; |
|
|
|
if (text[*index_in_text] == '(' || text[*index_in_text] == '\'' ) { |
|
|
|
try { |
|
|
|
@@ -208,12 +230,14 @@ Ast_Node* parse_expression(char* text, int* index_in_text) { |
|
|
|
create_ast_node_pair(result, create_ast_node_nil())); |
|
|
|
} |
|
|
|
++(*index_in_text); |
|
|
|
++parser_col; |
|
|
|
|
|
|
|
eat_whitespace(text, index_in_text); |
|
|
|
|
|
|
|
// if there was actually nothing in the list, return nil |
|
|
|
if (text[(*index_in_text)] == ')') { |
|
|
|
++(*index_in_text); |
|
|
|
++parser_col; |
|
|
|
return create_ast_node_nil(); |
|
|
|
} |
|
|
|
|
|
|
|
@@ -236,16 +260,18 @@ Ast_Node* parse_expression(char* text, int* index_in_text) { |
|
|
|
|
|
|
|
eat_until_code(text, index_in_text); |
|
|
|
if (text[(*index_in_text)] == '\0') { |
|
|
|
create_error(Error_Type_Unexpected_Eof, create_source_code_location(parser_file, parser_line)); |
|
|
|
create_error(Error_Type_Unexpected_Eof, create_source_code_location(parser_file, parser_line, parser_col)); |
|
|
|
return nullptr; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (text[(*index_in_text)] == ')') { |
|
|
|
head->value.pair->rest = create_ast_node_nil(); |
|
|
|
++parser_col; |
|
|
|
++(*index_in_text); |
|
|
|
break; |
|
|
|
} else if (text[(*index_in_text)] == '.') { |
|
|
|
++parser_col; |
|
|
|
++(*index_in_text); |
|
|
|
eat_until_code(text, index_in_text); |
|
|
|
|
|
|
|
@@ -257,7 +283,8 @@ Ast_Node* parse_expression(char* text, int* index_in_text) { |
|
|
|
eat_until_code(text, index_in_text); |
|
|
|
|
|
|
|
if (text[(*index_in_text)] != ')') |
|
|
|
create_error(Error_Type_Syntax_Error, create_source_code_location(parser_file, parser_line)); |
|
|
|
create_error(Error_Type_Syntax_Error, create_source_code_location(parser_file, parser_line, parser_col)); |
|
|
|
++parser_col; |
|
|
|
++(*index_in_text); |
|
|
|
break; |
|
|
|
} else { |
|
|
|
@@ -269,6 +296,10 @@ Ast_Node* parse_expression(char* text, int* index_in_text) { |
|
|
|
} |
|
|
|
|
|
|
|
Ast_Node* parse_single_expression(char* text) { |
|
|
|
parser_file = "stdin"; |
|
|
|
parser_line = 1; |
|
|
|
parser_col = 1; |
|
|
|
|
|
|
|
int index_in_text = 0; |
|
|
|
Ast_Node* result; |
|
|
|
eat_until_code(text, &index_in_text); |
|
|
|
@@ -283,13 +314,16 @@ Ast_Node* parse_single_expression(char* text) { |
|
|
|
eat_until_code(text, &index_in_text); |
|
|
|
if (text[(index_in_text)] == '\0') |
|
|
|
return result; |
|
|
|
create_error(Error_Type_Trailing_Garbage, create_source_code_location(parser_file, parser_line)); |
|
|
|
create_error(Error_Type_Trailing_Garbage, create_source_code_location(parser_file, parser_line, parser_col)); |
|
|
|
return nullptr; |
|
|
|
} |
|
|
|
|
|
|
|
Ast_Node_Array_List* parse_program(char* file_name, char* text) { |
|
|
|
parser_file = (char*)malloc(strlen(file_name) * sizeof(char) + 1); |
|
|
|
strcpy(parser_file, file_name); |
|
|
|
parser_line = 1; |
|
|
|
parser_col = 0; |
|
|
|
|
|
|
|
Ast_Node_Array_List* program = create_Ast_Node_Array_List(16); |
|
|
|
|
|
|
|
int index_in_text = 0; |
|
|
|
@@ -312,9 +346,11 @@ Ast_Node_Array_List* parse_program(char* file_name, char* text) { |
|
|
|
} break; |
|
|
|
default: |
|
|
|
/* syntax error */ |
|
|
|
create_error(Error_Type_Syntax_Error, create_source_code_location(parser_file, parser_line)); |
|
|
|
create_error(Error_Type_Syntax_Error, create_source_code_location(parser_file, parser_line, parser_col)); |
|
|
|
return nullptr; |
|
|
|
} |
|
|
|
} |
|
|
|
return program; |
|
|
|
} |
|
|
|
|
|
|
|
#undef inject_scl |