204 lines
4.6 KiB
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;
|
|
}
|