foxp/src/parser.c

204 lines
4.6 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
#include "parser.h"
#include "extstring.h"
struct SyntaxElement* se_init(void) {
struct SyntaxElement* syntaxelement = malloc(sizeof(struct SyntaxElement));
syntaxelement->type = NONE;
syntaxelement->content = NULL;
syntaxelement->next = NULL;
syntaxelement->top = NULL;
return syntaxelement;
}
struct SyntaxElement* se_bottom(struct SyntaxElement* syntaxelement) {
syntaxelement->content = se_init();
((struct SyntaxElement*)syntaxelement->content)->top = syntaxelement;
return ((struct SyntaxElement*)syntaxelement->content);
}
struct SyntaxElement* se_next(struct SyntaxElement* syntaxelement) {
syntaxelement->next = se_init();
syntaxelement->next->top = syntaxelement->top;
return syntaxelement->next;
}
void se_free(struct SyntaxElement* syntaxtree) {
switch (syntaxtree->type) {
case NONE:
free(syntaxtree);
return;
case TREE:
case TOPTREE:
if (syntaxtree->content != NULL) {
se_free((struct SyntaxElement*)syntaxtree->content);
}
break;
default:
free(syntaxtree->content);
break;
}
if (syntaxtree->next != NULL) {
se_free(syntaxtree->next);
}
free(syntaxtree);
}
void se_clean(struct SyntaxElement* syntaxtree) {
if (syntaxtree->next != NULL) {
switch (syntaxtree->next->type) {
case NONE:
free(syntaxtree->next);
syntaxtree->next = NULL;
break;
default:
se_clean(syntaxtree->next);
break;
}
}
if (syntaxtree->content != NULL && (syntaxtree->type == TOPTREE || syntaxtree->type == TREE)) {
switch (((struct SyntaxElement*)syntaxtree->content)->type) {
case NONE:
free(syntaxtree->content);
syntaxtree->content = NULL;
break;
default:
se_clean((struct SyntaxElement*)syntaxtree->content);
break;
}
}
}
struct SyntaxElement* parse(FILE* file) {
struct SyntaxElement* syntaxtree = se_init();
struct SyntaxElement* syntaxtreestart = syntaxtree;
syntaxtree->type = TOPTREE;
char symbol;
bool intree = false;
bool incomment = false;
bool instring = false;
bool intoken = false;
struct Extstring* token = NULL;
struct Extstring* string = NULL;
while (1) {
symbol = fgetc(file);
if (feof(file))
break;
if (incomment) {
if (symbol == '\n')
incomment = false;
continue;
}
if (instring) {
if (symbol == '"') {
if (string == NULL) {
string = malloc(sizeof(struct Extstring));
string->next = NULL;
}
instring = false;
syntaxtree->type = STRING;
char* sstring = es_tostring(string);
syntaxtree->content = sstring;
es_free(string);
string = NULL;
syntaxtree = se_next(syntaxtree);
} else {
if (string == NULL) {
string = malloc(sizeof(struct Extstring));
string->symbol = symbol;
string->next = NULL;
continue;
}
es_addsymbol(string, symbol);
}
continue;
}
if (intoken) {
if (isspace(symbol) || symbol == '(' || symbol == ')') {
intoken = false;
syntaxtree->type = TOKEN;
char* sstring = es_tostring(token);
syntaxtree->content = sstring;
es_free(token);
token = NULL;
syntaxtree = se_next(syntaxtree);
} else {
es_addsymbol(token, symbol);
continue;
}
}
if (isspace(symbol))
continue;
if (intree) {
switch (symbol) {
case '(':
syntaxtree = se_bottom(syntaxtree);
break;
case ')':
if (syntaxtree->top->type == TOPTREE) {
intree = false;
syntaxtree = syntaxtree->top;
syntaxtree = se_next(syntaxtree);
syntaxtree->type = TOPTREE;
} else {
syntaxtree = syntaxtree->top;
syntaxtree = se_next(syntaxtree);
syntaxtree->type = TREE;
}
break;
case ';':
incomment = true;
continue;
case '"':
instring = true;
continue;
default:
token = malloc(sizeof(struct Extstring));
token->symbol = symbol;
token->next = NULL;
intoken = true;
break;
}
continue;
} else {
switch (symbol) {
case ')':
fprintf(stderr, "Unbalanced brackets.\n");
return NULL;
case ';':
incomment = true;
continue;
case '(':
intree = true;
syntaxtree = se_bottom(syntaxtree);
syntaxtree->type = TREE;
continue;
default:
fprintf(stderr, "Expression outside of brackets.\n");
return NULL;
}
}
}
if (intree) {
fprintf(stderr, "Unexpected EOF.\n");
return NULL;
}
syntaxtree = syntaxtreestart;
while (1) {
if (syntaxtree->next->next == NULL) {
free(syntaxtree->next);
syntaxtree->next = NULL;
break;
}
syntaxtree = syntaxtree->next;
}
se_clean(syntaxtreestart);
return syntaxtreestart;
}