#include #include #include #include #include #include #include "precedent.h" #include "hashtable.h" #include "parse.h" #include "eval.h" #include "compile.h" int main(int argc, char** argv) { clock_t initTime = clock(); char visual = 0; char debug = 0; char compiled = 0; if (argc > 1) { for (int i = 1; i < argc; i++) { if (strcmp("--version", argv[i]) == 0) { printf("precedent, version 1.0\n"); printf("Copyright 2023 Kai Stevenson\n"); printf("All rights reserved. No part of the software may be sold\nor used in derivative works without explicit consent\n"); return 0; } else if (strcmp("--help", argv[i]) == 0) { printf("usage: precedent [--visualize] [--debug] [--version] [--help]\n"); return 0; } else if (strcmp("--visualize", argv[i]) == 0) { visual = 1; } else if (strcmp("--debug", argv[i]) == 0) { debug = 1; } else if (strcmp("--compiled", argv[i]) == 0) { compiled = 1; } } } else { printf("usage: precedent [--visualize] [--version] [--help]\n"); return 0; } /* dirname may modify path, copy first */ char* path = argv[1]; char* pathCpy = malloc((strlen(path) + 1) * sizeof(char)); strcpy(pathCpy, path); char* dirName = dirname(pathCpy); char* baseDir = malloc((strlen(dirName) + 2) * sizeof(char)); strcpy(baseDir, dirName); strcat(baseDir, "/"); hashtable_t* includeTable = init_hashtable(500, NULL); char* baseContent = read_file(path); char* finalContent = preprocess(baseContent, baseDir, includeTable); destroy_hashtable(includeTable); /* TODO: write hashtable information if debug */ sym_t* finalSymbol = parse_symbol_final(finalContent); free(pathCpy); free(baseDir); free(finalContent); if (visual) { printf("--BEGIN VISUALIZATION--\n"); write_symbol_visual(finalSymbol, 0); printf("--END VISUALIZATION--\n"); } if (compiled) { char* res = compile_to_asm(finalSymbol); destroy_sym_tree(finalSymbol); printf("%s\n", res); } else { hashtable_t* rootTable = init_hashtable(500, NULL); clock_t setupTime = clock(); sym_t* sym = eval(finalSymbol, rootTable); clock_t evalTime = clock(); if (debug) { printf("time taken to set up environment: %.5f secs\n", (float)(setupTime - initTime) / (float)CLOCKS_PER_SEC); printf("time taken to execute program: %.5f secs\n", ((float)(evalTime - setupTime) - initTime) / (float)CLOCKS_PER_SEC); } destroy_sym_tree(finalSymbol); destroy_sym(sym); destroy_hashtable(rootTable); } return 0; } char* read_file(char* path) { FILE* file = fopen(path, "r"); if (file == NULL) { printf("file %s does not exist\n", path); } fseek(file, 0, SEEK_END); unsigned long int length = ftell(file); fseek(file, 0, SEEK_SET); char* out = malloc((length + 1) * sizeof(char)); fread(out, length, 1, file); fclose(file); out[length] = '\0'; return out; } char* preprocess(char* str, char* baseDir, hashtable_t* includeHt) { while (1) { int i = 0; while (str[i] != '@' && str[i] != '&') { i++; if (str[i] == '\0') { return str; } } char alwaysInclude = 0; /* include even if already included */ if (str[i] == '&') { alwaysInclude = 1; } str[i] = ' '; i++; char* includeName = malloc(40 * sizeof(char)); int f = 0; while (isalnum((unsigned char)str[i]) || str[i] == '/' || str[i] == '.' || str[i] == '_') { includeName[f] = str[i]; str[i] = ' '; i++; f++; } includeName[f] = '\0'; char* path = malloc((strlen(baseDir) + strlen(includeName) + 1) * sizeof(char)); strcpy(path, baseDir); strcat(path, includeName); char* fileContent = read_file(path); /* ensure the file has not already been included */ char notIncluded = hashtable_get_pair(includeHt, fileContent).key == NULL; if (notIncluded) { hashtable_add_pair(includeHt, init_pair(fileContent, NULL)); } if (notIncluded || alwaysInclude) { /* TODO: fix relative paths */ char* toInclude = preprocess(fileContent, baseDir, includeHt); char* newStr = malloc((strlen(toInclude) + strlen(str) + 1) * sizeof(char)); strcpy(newStr, toInclude); strcat(newStr, str); free(str); free(toInclude); str = newStr; } else { free(fileContent); } free(includeName); free(path); } }