#include #include #include #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; }