496 lines
11 KiB
C
496 lines
11 KiB
C
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
|
|
#include "syntax.h"
|
|
|
|
void string_append(char** string, char* append) {
|
|
|
|
int len = strlen(*string);
|
|
|
|
*string = realloc(*string, len + strlen(append) + sizeof(char));
|
|
strcpy(*string + len, append);
|
|
|
|
}
|
|
|
|
void string_append_char(char** string, char append) {
|
|
|
|
int len = strlen(*string);
|
|
|
|
*string = realloc(*string, len + 2 * sizeof(char));
|
|
string[0][len] = append;
|
|
string[0][len + 1] = '\0';
|
|
}
|
|
|
|
char* string_unescape(char* string) {
|
|
char* tmp = calloc(1,sizeof(char));
|
|
|
|
size_t len = strlen(string);
|
|
|
|
for (size_t i = 0; i < len; i++) {
|
|
|
|
if (string[i] == '\\')
|
|
i++;
|
|
string_append_char(&tmp, string[i]);
|
|
|
|
}
|
|
|
|
return tmp;
|
|
}
|
|
|
|
void string_append_free(char** string, char* append) {
|
|
string_append(string, append);
|
|
free(append);
|
|
}
|
|
|
|
void compile_enter_tag(char** string) {
|
|
|
|
int len = strlen(*string);
|
|
|
|
*string = realloc(*string, len + 3 * sizeof(char));
|
|
|
|
string[0][len + 0] = '{';
|
|
string[0][len + 1] = '%';
|
|
string[0][len + 2] = '\0';
|
|
|
|
}
|
|
|
|
void compile_exit_tag(char** string) {
|
|
|
|
int len = strlen(*string);
|
|
|
|
*string = realloc(*string, len + 3 * sizeof(char));
|
|
|
|
string[0][len + 0] = '%';
|
|
string[0][len + 1] = '}';
|
|
string[0][len + 2] = '\0';
|
|
|
|
}
|
|
|
|
bool compile_isop(char* string) {
|
|
|
|
if (strcmp(string, "+") == 0) return true;
|
|
|
|
else if (strcmp(string, "-") == 0) return true;
|
|
else if (strcmp(string, "*") == 0) return true;
|
|
else if (strcmp(string, "/") == 0) return true;
|
|
else if (strcmp(string, "**") == 0) return true;
|
|
else if (strcmp(string, "//") == 0) return true;
|
|
else if (strcmp(string, "%") == 0) return true;
|
|
else if (strcmp(string, ".") == 0) return true;
|
|
else if (strcmp(string, "~") == 0) return true;
|
|
else if (strcmp(string, "<") == 0) return true;
|
|
else if (strcmp(string, ">") == 0) return true;
|
|
else if (strcmp(string, "<=") == 0) return true;
|
|
else if (strcmp(string, ">=") == 0) return true;
|
|
else if (strcmp(string, "==") == 0) return true;
|
|
else if (strcmp(string, "!=") == 0) return true;
|
|
else if (strcmp(string, "and") == 0) return true;
|
|
else if (strcmp(string, "or") == 0) return true;
|
|
else if (strcmp(string, "|") == 0) return true;
|
|
else if (strcmp(string, ":?") == 0) return true;
|
|
|
|
else return false;
|
|
|
|
}
|
|
|
|
char* compile_bracket_wrap(char* string) {
|
|
char* new = malloc(sizeof(char));
|
|
new[0] = '\0';
|
|
string_append(&new,"(");
|
|
string_append(&new,string);
|
|
string_append(&new,")");
|
|
free(string);
|
|
return new;
|
|
}
|
|
|
|
char* compile_expression(tSyntaxElement* syntaxelement);
|
|
|
|
char* compile_expression_wrapped(tSyntaxElement* syntaxelement) {
|
|
return compile_bracket_wrap(compile_expression(syntaxelement));
|
|
}
|
|
|
|
void compile_genexec(char** result, tSyntaxElement* se){
|
|
|
|
tSyntaxElement* token = se;
|
|
|
|
string_append(result,"(");
|
|
|
|
token = token->next;
|
|
|
|
while (1) {
|
|
|
|
if (token != NULL) {
|
|
|
|
string_append_free(result,compile_expression(token));
|
|
|
|
if (token->next != NULL)
|
|
string_append(result,",");
|
|
|
|
token = token->next;
|
|
|
|
} else break;
|
|
|
|
}
|
|
|
|
string_append(result,")");
|
|
}
|
|
|
|
char* compile_gensplit(tSyntaxElement* se, char* operator) {
|
|
tSyntaxElement* token = se;
|
|
char* result = malloc(sizeof(char));
|
|
result[0] = '\0';
|
|
while (1) {
|
|
|
|
if (token->next != NULL) {
|
|
|
|
if (token->next->type == TOKEN)
|
|
string_append(&result,token->next->content.string);
|
|
else
|
|
string_append(&result,compile_expression_wrapped(token->next));
|
|
|
|
if (token->next->next != NULL)
|
|
string_append(&result,operator);
|
|
|
|
token = token->next;
|
|
|
|
} else break;
|
|
|
|
}
|
|
return result;
|
|
}
|
|
|
|
char* compile_expression(tSyntaxElement* syntaxelement) {
|
|
|
|
char* result = calloc(1,sizeof(char));
|
|
|
|
switch (syntaxelement->type) {
|
|
|
|
case TOKEN:
|
|
|
|
string_append(&result, syntaxelement->content.string);
|
|
break;
|
|
|
|
case STRING:
|
|
|
|
string_append(&result, "\"");
|
|
string_append(&result, syntaxelement->content.string);
|
|
string_append(&result, "\"");
|
|
|
|
break;
|
|
|
|
case TREE:
|
|
|
|
if (se_istraversable(syntaxelement)) {
|
|
|
|
switch (syntaxelement->content.syntax->type) {
|
|
|
|
case TOKEN: {
|
|
|
|
tSyntaxElement* token = syntaxelement->content.syntax;
|
|
|
|
if (compile_isop(token->content.string)) {
|
|
|
|
char* operator = token->content.string;
|
|
|
|
string_append_free(&result, compile_gensplit(token, operator));
|
|
|
|
} else {
|
|
|
|
if (strcmp(token->content.string, "if") == 0) {
|
|
|
|
string_append_free(&result,compile_expression_wrapped(token->next));
|
|
string_append(&result,"?");
|
|
|
|
string_append_free(&result,compile_expression_wrapped(token->next->next));
|
|
string_append(&result,":");
|
|
|
|
string_append_free(&result,compile_expression_wrapped(token->next->next->next));
|
|
|
|
} else if (strcmp(token->content.string, "get") == 0) {
|
|
|
|
string_append_free(&result,compile_expression(token->next));
|
|
string_append(&result,"[");
|
|
string_append_free(&result,compile_expression(token->next->next));
|
|
string_append(&result,"]");
|
|
|
|
} else if (strcmp(token->content.string, "neg") == 0) {
|
|
|
|
string_append(&result,"-");
|
|
string_append_free(&result,compile_expression_wrapped(token->next));
|
|
|
|
} else if (strcmp(token->content.string, "not") == 0) {
|
|
|
|
string_append(&result,"not");
|
|
string_append_free(&result,compile_expression_wrapped(token->next));
|
|
|
|
} else if (strcmp(token->content.string, "list") == 0) {
|
|
|
|
string_append(&result,"[");
|
|
string_append_free(&result,compile_gensplit(token, ","));
|
|
string_append(&result,"]");
|
|
|
|
} else if (strcmp(token->content.string, "map") == 0) {
|
|
|
|
string_append(&result,"{");
|
|
|
|
for (tSyntaxElement* i = token->next; i != NULL; i = i->next) {
|
|
|
|
string_append_free(&result, compile_expression(i->content.syntax));
|
|
string_append(&result, ":");
|
|
string_append_free(&result, compile_expression(i->content.syntax->next));
|
|
|
|
if (i->next != NULL)
|
|
string_append(&result,",");
|
|
|
|
}
|
|
|
|
string_append(&result,"}");
|
|
|
|
} else {
|
|
|
|
string_append(&result,token->content.string);
|
|
compile_genexec(&result, token);
|
|
|
|
}
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
case TREE: {
|
|
tSyntaxElement* token = syntaxelement->content.syntax;
|
|
string_append_free(&result, compile_expression(syntaxelement->content.syntax));
|
|
compile_genexec(&result, token);
|
|
break;
|
|
}
|
|
|
|
case STRING:
|
|
return NULL;
|
|
case NONE:
|
|
case NEWTREE:
|
|
string_append(&result, "()");
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
string_append(&result, "()");
|
|
}
|
|
|
|
break;
|
|
|
|
case NEWTREE:
|
|
case NONE:
|
|
string_append(&result, "()");
|
|
break;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
char* compile(tSyntaxElement* syntaxtree) {
|
|
|
|
char* result = calloc(1,sizeof(char));
|
|
|
|
while (1) {
|
|
|
|
if (se_istraversable(syntaxtree)) {
|
|
|
|
if (syntaxtree->content.syntax->type == TOKEN) {
|
|
|
|
tSyntaxElement* token = syntaxtree->content.syntax;
|
|
|
|
if (strcmp(token->content.string, "#def") == 0) {
|
|
} else if (strcmp(token->content.string, "set") == 0) {
|
|
|
|
compile_enter_tag(&result);
|
|
|
|
string_append(&result, "set ");
|
|
string_append(&result,token->next->content.string);
|
|
string_append(&result,"=");
|
|
string_append_free(&result,compile_expression_wrapped(token->next->next));
|
|
|
|
compile_exit_tag(&result);
|
|
|
|
} else if (strcmp(token->content.string, "global") == 0) {
|
|
|
|
compile_enter_tag(&result);
|
|
|
|
string_append(&result, "global ");
|
|
string_append(&result,token->next->content.string);
|
|
string_append(&result,"=");
|
|
string_append_free(&result,compile_expression_wrapped(token->next->next));
|
|
|
|
compile_exit_tag(&result);
|
|
|
|
} else if (strcmp(token->content.string, "do") == 0) {
|
|
|
|
compile_enter_tag(&result);
|
|
|
|
string_append(&result, "do ");
|
|
string_append_free(&result,compile_expression(token->next));
|
|
|
|
compile_exit_tag(&result);
|
|
|
|
} else if (strcmp(token->content.string, "use") == 0) {
|
|
|
|
compile_enter_tag(&result);
|
|
|
|
string_append(&result, "use ");
|
|
string_append_free(&result,compile_expression(token->next));
|
|
|
|
compile_exit_tag(&result);
|
|
|
|
} else if (strcmp(token->content.string, "if") == 0) {
|
|
|
|
compile_enter_tag(&result);
|
|
|
|
string_append(&result, "if ");
|
|
string_append_free(&result,compile_expression(token->next));
|
|
|
|
compile_exit_tag(&result);
|
|
|
|
string_append_free(&result,compile(token->next->next));
|
|
|
|
if (token->next->next->next != NULL) {
|
|
|
|
compile_enter_tag(&result);
|
|
string_append(&result, "else");
|
|
compile_exit_tag(&result);
|
|
|
|
string_append_free(&result,compile(token->next->next->next));
|
|
|
|
}
|
|
|
|
compile_enter_tag(&result);
|
|
|
|
string_append(&result, "endif");
|
|
|
|
compile_exit_tag(&result);
|
|
|
|
} else if (strcmp(token->content.string, "print") == 0) {
|
|
|
|
for(tSyntaxElement* i = token->next; i != NULL; i = i->next) {
|
|
|
|
string_append(&result, "{{");
|
|
string_append_free(&result,compile_expression(i));
|
|
string_append(&result, "}}");
|
|
|
|
}
|
|
|
|
} else if (strcmp(token->content.string, "fn") == 0) {
|
|
|
|
compile_enter_tag(&result);
|
|
|
|
string_append(&result, "macro ");
|
|
string_append_free(&result, compile_expression(token->next));
|
|
|
|
compile_exit_tag(&result);
|
|
|
|
|
|
string_append_free(&result, compile(token->next->next));
|
|
|
|
|
|
compile_enter_tag(&result);
|
|
|
|
string_append(&result, "endmacro");
|
|
|
|
compile_exit_tag(&result);
|
|
|
|
} else if (strcmp(token->content.string, "for") == 0) {
|
|
|
|
compile_enter_tag(&result);
|
|
|
|
string_append(&result, "for ");
|
|
string_append_free(&result, compile_expression(token->next->content.syntax));
|
|
string_append(&result, " in ");
|
|
string_append_free(&result, compile_expression(token->next->content.syntax->next));
|
|
|
|
compile_exit_tag(&result);
|
|
|
|
|
|
string_append_free(&result, compile(token->next->next));
|
|
|
|
|
|
compile_enter_tag(&result);
|
|
|
|
string_append(&result, "endfor");
|
|
|
|
compile_exit_tag(&result);
|
|
|
|
} else if (strcmp(token->content.string, "formap") == 0) {
|
|
|
|
compile_enter_tag(&result);
|
|
|
|
string_append(&result, "for ");
|
|
string_append_free(&result, compile_expression(token->next->content.syntax));
|
|
string_append(&result, ", ");
|
|
string_append_free(&result, compile_expression(token->next->content.syntax->next));
|
|
string_append(&result, " in ");
|
|
string_append_free(&result, compile_expression(token->next->content.syntax->next->next));
|
|
|
|
compile_exit_tag(&result);
|
|
|
|
|
|
string_append_free(&result, compile(token->next->next));
|
|
|
|
|
|
compile_enter_tag(&result);
|
|
|
|
string_append(&result, "endfor");
|
|
|
|
compile_exit_tag(&result);
|
|
|
|
} else if (strcmp(token->content.string, "verbatim") == 0) {
|
|
|
|
compile_enter_tag(&result);
|
|
string_append(&result, "verbatim");
|
|
compile_exit_tag(&result);
|
|
|
|
for(tSyntaxElement* i = token->next; i != NULL; i = i->next) {
|
|
|
|
string_append_free(&result,string_unescape(i->content.string));
|
|
|
|
}
|
|
|
|
compile_enter_tag(&result);
|
|
string_append(&result, " endverbatim");
|
|
compile_exit_tag(&result);
|
|
|
|
} else if (strcmp(token->content.string, "assert") == 0) {
|
|
|
|
compile_enter_tag(&result);
|
|
string_append(&result, "require ");
|
|
|
|
string_append_free(&result, compile_expression(token->next));
|
|
|
|
string_append(&result, " returning ");
|
|
|
|
string_append_free(&result, compile_expression(token->next->next));
|
|
compile_exit_tag(&result);
|
|
|
|
} else {
|
|
|
|
string_append(&result, "{#");
|
|
string_append(&result, "Unknown keyword: ");
|
|
string_append(&result, token->content.string);
|
|
string_append(&result, "#}");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (syntaxtree->next != NULL)
|
|
syntaxtree = syntaxtree->next;
|
|
else break;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|