diff --git a/.github/workflows/manual_valgrind.yml b/.github/workflows/manual_leakcheck.yml similarity index 71% rename from .github/workflows/manual_valgrind.yml rename to .github/workflows/manual_leakcheck.yml index 92fe86fe4..4efa60a97 100644 --- a/.github/workflows/manual_valgrind.yml +++ b/.github/workflows/manual_leakcheck.yml @@ -18,7 +18,12 @@ jobs: - name: Lib Install run: | sudo apt-get install valgrind - make all DEBUG=1 + - name: Run Asan + run: | + make all DEBUG=2 + ./build/dice d20 - name: Run Valgrind - run: valgrind --leak-check=full ./build/dice d20 + run: | + make all DEBUG=1 + valgrind --leak-check=full ./build/dice d20 diff --git a/.github/workflows/test_binding_cpp.yml b/.github/workflows/test_binding_cpp.yml index 203062445..932fcb738 100644 --- a/.github/workflows/test_binding_cpp.yml +++ b/.github/workflows/test_binding_cpp.yml @@ -16,7 +16,8 @@ jobs: - uses: actions/checkout@v3 - name: make run: | - make CC=clang all + clang --version + make CC=clang DEBUG=0 all ./build/dice d20 build_cpp: diff --git a/Makefile b/Makefile index 0d8ec2393..a4f3de903 100644 --- a/Makefile +++ b/Makefile @@ -11,11 +11,15 @@ else STANDARD= -std=c99 endif -OPT=-O3 $(STANDARD) -Wall -Wextra -Werror -pedantic -Wcast-align \ + + +OPT=-O3 \ + $(STANDARD) -Wall -Wextra -Werror -pedantic -Wcast-align \ -Wcast-qual -Wdisabled-optimization -Winit-self \ -Wmissing-declarations -Wmissing-include-dirs \ -Wredundant-decls -Wshadow -Wsign-conversion \ - -Wundef -Wno-unused -Wformat=2 + -Wundef -Wno-unused -Wformat=2 + # -ffast-math # Problematic for Python @@ -26,13 +30,35 @@ OPT=-O3 $(STANDARD) -Wall -Wextra -Werror -pedantic -Wcast-align \ # -Wlogical-op # === DEBUG OPTIONS ==== + +ASAN_FLAGS= -fsanitize=address \ + -fsanitize-recover=address \ + -fsanitize-address-use-after-scope \ + -fno-omit-frame-pointer -static-libasan -g +GDB_FLAGS= -g -gdwarf-5 + DEBUG=0 ifeq ($(DEBUG), 1) -OPT=-O0 -g # Valgrind info +# Valgrind +OPT=-O0 $(GDB_FLAGS) PARSER_DEBUG:=--debug --verbose else +ifeq ($(DEBUG), 2) +# ASAN +OPT=-O0 $(ASAN_FLAGS) +PARSER_DEBUG:= +else +ifeq ($(DEBUG), 3) +# ASAN +OPT=-O0 $(GDB_FLAGS) -lefence +PARSER_DEBUG:= +else +# USUAL PARSER_DEBUG:= endif +endif +endif + USE_SECURE_RANDOM=0 ifeq ($(USE_SECURE_RANDOM), 1) @@ -62,7 +88,7 @@ LEXER:=flex -f -Ca -Ce -Cr endif # add flags and the include paths -DEFS=-DUSE_SECURE_RANDOM=${USE_SECURE_RANDOM} -DJUST_YACC=${YACC_FALLBACK} -DBREAKDOWN +DEFS=-DUSE_SECURE_RANDOM=${USE_SECURE_RANDOM} -DJUST_YACC=${YACC_FALLBACK} CFLAGS=$(foreach D,$(INCDIRS),-I$(D)) $(OPT) $(DEFS) diff --git a/src/C++/main.cpp b/src/C++/main.cpp index 8bf53ac84..23effbe56 100644 --- a/src/C++/main.cpp +++ b/src/C++/main.cpp @@ -4,16 +4,6 @@ #include #include "shared_header.h" -int roll_full_options( - char* roll_request, - char* log_file, - int enable_verbosity, - int enable_introspection, - int enable_mocking, - int mocking_type, - int mocking_seed -); - int main() { const char* fn = "out.dice"; @@ -27,6 +17,7 @@ int main() 0, 0, 0, + 0, 0 ); assert(err_code == 0); diff --git a/src/grammar/rolls/dice_enums.h b/src/grammar/constructs/dice_enums.h similarity index 94% rename from src/grammar/rolls/dice_enums.h rename to src/grammar/constructs/dice_enums.h index 04990f270..d183043bf 100644 --- a/src/grammar/rolls/dice_enums.h +++ b/src/grammar/constructs/dice_enums.h @@ -1,18 +1,18 @@ -#ifndef __DICE_ENUMS_H__ -#define __DICE_ENUMS_H__ - -typedef enum { - // 0 is invalid - SYMBOLIC = 1, - NUMERIC = 2 -} DIE_TYPE; - -typedef enum { - NO_EXPLOSION = 0, - STANDARD_EXPLOSION = 1, - ONLY_ONCE_EXPLOSION = 2, - PENETRATING_EXPLOSION = 3, - DIMINISHING_EXPLOSION = 4 -} EXPLOSION_TYPE; - -#endif +#ifndef __DICE_ENUMS_H__ +#define __DICE_ENUMS_H__ + +typedef enum { + // 0 is invalid + SYMBOLIC = 1, + NUMERIC = 2 +} DIE_TYPE; + +typedef enum { + NO_EXPLOSION = 0, + STANDARD_EXPLOSION = 1, + ONLY_ONCE_EXPLOSION = 2, + PENETRATING_EXPLOSION = 3, + DIMINISHING_EXPLOSION = 4 +} EXPLOSION_TYPE; + +#endif diff --git a/src/grammar/rolls/dice_roll_structs.h b/src/grammar/constructs/roll_parameters.h similarity index 86% rename from src/grammar/rolls/dice_roll_structs.h rename to src/grammar/constructs/roll_parameters.h index f01e86bfd..cac7e04c1 100644 --- a/src/grammar/rolls/dice_roll_structs.h +++ b/src/grammar/constructs/roll_parameters.h @@ -1,15 +1,15 @@ -#ifndef __DICE_ROLL_STRUCTS_H__ -#define __DICE_ROLL_STRUCTS_H__ - -#include "dice_enums.h" - -typedef struct roll_params { - unsigned int number_of_dice; - unsigned int die_sides; - EXPLOSION_TYPE explode; - char** symbol_pool; - int start_value; - DIE_TYPE dtype; -} roll_params; - -#endif +#ifndef __DICE_ROLL_STRUCTS_H__ +#define __DICE_ROLL_STRUCTS_H__ + +#include "constructs/dice_enums.h" + +typedef struct roll_params { + unsigned int number_of_dice; + unsigned int die_sides; + EXPLOSION_TYPE explode; + char** symbol_pool; + int start_value; + DIE_TYPE dtype; +} roll_params; + +#endif diff --git a/src/grammar/rolls/vec.h b/src/grammar/constructs/vec.h similarity index 70% rename from src/grammar/rolls/vec.h rename to src/grammar/constructs/vec.h index 13ffa1b59..ed114d1d6 100644 --- a/src/grammar/rolls/vec.h +++ b/src/grammar/constructs/vec.h @@ -1,17 +1,19 @@ -#ifndef __VEC_H__ -#define __VEC_H__ - -#include "dice_enums.h" -#include "dice_roll_structs.h" - -typedef struct vec { - DIE_TYPE dtype; - int* content; - unsigned int length; - // TODO: Split length into content_length and symbol length - // maybe use union? If it exists in c - char** symbols; - roll_params source; -} vec; - -#endif +#ifndef __VEC_H__ +#define __VEC_H__ + +#include "constructs/dice_enums.h" +#include "constructs/roll_parameters.h" +#include + +typedef struct vec { + DIE_TYPE dtype; + int* content; + unsigned int length; + // TODO: Split length into content_length and symbol length + // maybe use union? If it exists in c + char** symbols; + roll_params source; + bool has_source; +} vec; + +#endif diff --git a/src/grammar/dice.lex b/src/grammar/dice.lex index 7899f071e..6f821d5b0 100644 --- a/src/grammar/dice.lex +++ b/src/grammar/dice.lex @@ -6,7 +6,7 @@ #include #include "shared_header.h" #include "util/safe_functions.h" - #include "operations/condition_checking.h" + #include "operations/conditionals.h" #include "y.tab.h" #include @@ -31,6 +31,7 @@ vector.dtype = SYMBOLIC; vector.length = 1; + vector.has_source = false; yylval.values = vector; return CAPITAL_STRING; @@ -43,6 +44,7 @@ vector.content[0] = fast_atoi(yytext); + vector.has_source = false; vector.dtype = NUMERIC; vector.length = 1; yylval.values = vector; @@ -58,40 +60,53 @@ d { } (dF|df)\.1 { - char * plus, *minus, *zero; - plus = (char *)safe_malloc(sizeof(char *)); + char *plus, *minus; + char *zeroA, *zeroB, *zeroC, *zeroD; + plus = (char *)safe_calloc(sizeof(char *),MAX_SYMBOL_LENGTH); if(gnoll_errno){yyerror("Memory Err");} - plus = "+"; - zero = (char *)safe_malloc(sizeof(char *)); + plus[0] = '+'; + + zeroA = (char *)safe_calloc(sizeof(char *),MAX_SYMBOL_LENGTH); + if(gnoll_errno){yyerror("Memory Err");} + zeroA[0] = '0'; + zeroB = (char *)safe_calloc(sizeof(char *),MAX_SYMBOL_LENGTH); + if(gnoll_errno){yyerror("Memory Err");} + zeroB[0] = '0'; + zeroC = (char *)safe_calloc(sizeof(char *),MAX_SYMBOL_LENGTH); if(gnoll_errno){yyerror("Memory Err");} - zero = "0"; - minus = (char *)safe_malloc(sizeof(char *)); + zeroC[0] = '0'; + zeroD = (char *)safe_calloc(sizeof(char *),MAX_SYMBOL_LENGTH); if(gnoll_errno){yyerror("Memory Err");} - minus = "-"; + zeroD[0] = '0'; + + minus = (char *)safe_calloc(sizeof(char *),MAX_SYMBOL_LENGTH); + if(gnoll_errno){yyerror("Memory Err");} + minus[0] = '-'; vec vector; vector.dtype = SYMBOLIC; vector.symbols = (char**)safe_malloc(sizeof(char **) * 6); if(gnoll_errno){yyerror("Memory Err");} vector.symbols[0] = plus; - vector.symbols[1] = zero; - vector.symbols[2] = zero; - vector.symbols[3] = zero; - vector.symbols[4] = zero; + vector.symbols[1] = zeroA; + vector.symbols[2] = zeroB; + vector.symbols[3] = zeroC; + vector.symbols[4] = zeroD; vector.symbols[5] = minus; vector.length = 6; + vector.has_source = false; yylval.values = vector; return(FATE_DIE); } (dF|df)\.[3-9] { char * plus, *minus; - plus = (char *)safe_malloc(sizeof(char *)); + plus = (char *)safe_calloc(sizeof(char *),MAX_SYMBOL_LENGTH); if(gnoll_errno){yyerror("Memory Err");} - plus = "+"; - minus = (char *)safe_malloc(sizeof(char *)); + plus[0] = '+'; + minus = (char *)safe_calloc(sizeof(char *),MAX_SYMBOL_LENGTH); if(gnoll_errno){yyerror("Memory Err");} - minus = "-"; + minus[0] = '-'; vec vector; vector.dtype = SYMBOLIC; @@ -100,21 +115,22 @@ d { vector.symbols[0] = plus; vector.symbols[1] = minus; vector.length = 2; + vector.has_source = false; yylval.values = vector; return(FATE_DIE); } (dF|df)(\.2)? { - char * plus, *minus, *zero; - plus = (char *)safe_malloc(sizeof(char *)); + char *plus, *minus, *zero; + plus = (char *)safe_calloc(sizeof(char *),MAX_SYMBOL_LENGTH); if(gnoll_errno){yyerror("Memory Err");} - plus = "+"; - zero = (char *)safe_malloc(sizeof(char *)); + plus[0] = '+'; + zero = (char *)safe_calloc(sizeof(char *),MAX_SYMBOL_LENGTH); if(gnoll_errno){yyerror("Memory Err");} - zero = "0"; - minus = (char *)safe_malloc(sizeof(char *)); + zero[0] = '0'; + minus = (char *)safe_calloc(sizeof(char *),MAX_SYMBOL_LENGTH); if(gnoll_errno){yyerror("Memory Err");} - minus = "-"; + minus[0] = '-'; vec vector; vector.dtype = SYMBOLIC; @@ -123,7 +139,9 @@ d { vector.symbols[0] = plus; vector.symbols[1] = zero; vector.symbols[2] = minus; + vector.has_source = false; vector.length = 3; + vector.has_source = false; yylval.values = vector; return(FATE_DIE); @@ -197,6 +215,7 @@ u { vector.content[0] = IS_UNIQUE; vector.dtype = NUMERIC; vector.length = 1; + vector.has_source = false; yylval.values = vector; return (UNIQUE); } @@ -223,6 +242,7 @@ o { vector.content[0] = NOT_EQUAL; vector.dtype = NUMERIC; vector.length = 1; + vector.has_source = false; yylval.values = vector; return NE; } @@ -233,6 +253,7 @@ o { vector.content[0] = EQUALS; vector.dtype = NUMERIC; vector.length = 1; + vector.has_source = false; yylval.values = vector; return EQ; } @@ -243,6 +264,7 @@ o { vector.content[0] = LESS_THAN; vector.dtype = NUMERIC; vector.length = 1; + vector.has_source = false; yylval.values = vector; return LT; } @@ -252,6 +274,7 @@ o { if(gnoll_errno){yyerror("Memory Err");} vector.content[0] = GREATER_THAN; vector.dtype = NUMERIC; + vector.has_source = false; vector.length = 1; yylval.values = vector; return GT; @@ -263,6 +286,7 @@ o { vector.content[0] = LESS_OR_EQUALS; vector.dtype = NUMERIC; vector.length = 1; + vector.has_source = false; yylval.values = vector; return(LE); } @@ -273,6 +297,7 @@ o { vector.content[0] = GREATER_OR_EQUALS; vector.dtype = NUMERIC; vector.length = 1; + vector.has_source = false; yylval.values = vector; return(GE); } @@ -283,6 +308,7 @@ is_even { vector.content[0] = IF_EVEN; vector.dtype = NUMERIC; vector.length = 1; + vector.has_source = false; yylval.values = vector; return(IS_EVEN); } @@ -293,6 +319,7 @@ is_odd { vector.content[0] = IF_ODD; vector.dtype = NUMERIC; vector.length = 1; + vector.has_source = false; yylval.values = vector; return(IS_ODD); } diff --git a/src/grammar/dice.yacc b/src/grammar/dice.yacc index cb3e8ae7b..cc90a0d6c 100644 --- a/src/grammar/dice.yacc +++ b/src/grammar/dice.yacc @@ -8,35 +8,38 @@ #include #include #include -#include "yacc_header.h" -#include "util/vector_functions.h" -#include "shared_header.h" -#include "rolls/dice_logic.h" -#include "util/safe_functions.h" -#include "operations/macro_logic.h" -#include "rolls/sided_dice.h" -#include "rolls/mocking.h" -#include "operations/condition_checking.h" +#include #include +#include "shared_header.h" #include "external/pcg_basic.h" +#include "external/tinydir.h" +#include "operations/macros.h" +#include "operations/conditionals.h" +#include "rolls/dice_core.h" +#include "rolls/dice_frontend.h" +#include "util/mocking.h" +#include "util/safe_functions.h" +#include "util/array_functions.h" +#include "util/vector_functions.h" +#include "util/string_functions.h" #define UNUSED(x) (void)(x) -#define MAX(x, y) (((x) > (y)) ? (x) : (y)) -#define MIN(x, y) (((x) < (y)) ? (x) : (y)) -#define ABS(x) (((x) < 0) ? (-x) : (x)) +// Avoid conflicts with MacOs predefined macros +#define MAXV(x, y) (((x) > (y)) ? (x) : (y)) +#define MINV(x, y) (((x) < (y)) ? (x) : (y)) +#define ABSV(x) (((x) < 0) ? (-x) : (x)) int yylex(void); int yyerror(const char* s); int yywrap(); //TODO: move to external file -char * concat_strings(char ** s, int num_s); #ifdef JUST_YACC int yydebug=1; #endif -int verbose = 1; +int verbose = 0; int dice_breakdown = 0; int seeded = 0; int write_to_file = 0; @@ -46,10 +49,10 @@ extern int gnoll_errno; extern struct macro_struct *macros; pcg32_random_t rng; -// Registers - -// TODO: It would be better to fit arbitrary length strings. +// Function Signatures for this file +int initialize(); +// Functions int initialize(){ if (!seeded){ unsigned long int tick = (unsigned long)time(0)+(unsigned long)clock(); @@ -63,20 +66,11 @@ int initialize(){ return 0; } -int collapse(int * arr, unsigned int len){ - return sum(arr, len); -} - -int sum(int * arr, unsigned int len){ - int result = 0; - for(unsigned int i = 0; i != len; i++) result += arr[i]; - return result; -} - %} -%start gnoll_statement +%start gnoll_entry +/* %start gnoll_statement */ %token NUMBER SIDED_DIE FATE_DIE REPEAT SIDED_DIE_ZERO %token EXPLOSION IMPLOSION PENETRATE ONCE @@ -109,9 +103,17 @@ int sum(int * arr, unsigned int len){ %% /* Rules Section */ +gnoll_entry: + gnoll_statement{ + free_vector($1); + } +; gnoll_statement: - gnoll_statement STATEMENT_SEPERATOR gnoll_statement + gnoll_statement STATEMENT_SEPERATOR gnoll_statement{ + free_vector($3); + // vec1 freed at root. + } | /* Allow ending with ; */ gnoll_statement STATEMENT_SEPERATOR @@ -135,24 +137,41 @@ sub_statement: macro_statement: MACRO_STORAGE CAPITAL_STRING ASSIGNMENT math{ + /** + * MACRO_STORAGE - the symbol '#'' + * CAPITAL_STRING - vector + * ASSIGNMENT - the symbol '=' + * math - vector dice roll assignment + * returns - nothing. + */ vec key = $2; vec value = $4; register_macro(&key, &value.source); + + // Cleanup + free_vector(key); + free_vector(value); if(gnoll_errno){ YYABORT; yyclearin; } + vec null_vec; + light_initialize_vector(&null_vec, NUMERIC, 0); + $$ = null_vec; } ; -dice_statement: functions{ +dice_statement: math{ + /** + * functions a vector + * return NULL + */ vec vector = $1; - vec new_vec = vector; // Code Smell. - // Target Vector should be empty + vec new_vec; // Step 1: Collapse pool to a single value if nessicary collapse_vector(&vector, &new_vec); @@ -202,23 +221,86 @@ dice_statement: functions{ if(write_to_file){ fclose(fp); } + + free_vector(vector); + + $$ = new_vec; }; -functions: - function -; math: + FN_MAX LBRACE math SYMBOL_SEPERATOR math RBRACE{ + /** @brief performs the min(__, __) function + * @FN_MAX the symbol "max" + * @LBRACE the symbol "(" + * function The target vector + * SYMBOL_SEPERATOR the symbol "," + * function The target vector + * @RBRACE the symbol ")" + * return vector + */ + vec new_vec; + initialize_vector(&new_vec, NUMERIC, 1); + int vmax = MAXV( + $3.content[0], + $5.content[0] + ); + new_vec.content[0] = vmax; + $$ = new_vec; + free_vector($3); + free_vector($5); + } + | + FN_MIN LBRACE math SYMBOL_SEPERATOR math RBRACE{ + /** @brief performs the min(__, __) function + * @FN_MIN the symbol "min" + * @LBRACE the symbol "(" + * function The target vector + * SYMBOL_SEPERATOR the symbol "," + * function The target vector + * @RBRACE the symbol ")" + * return vector + */ + vec new_vec; + initialize_vector(&new_vec, NUMERIC, 1); + new_vec.content[0] = MINV( + $3.content[0], + $5.content[0] + ); + $$ = new_vec; + free_vector($3); + free_vector($5); + } + | + FN_ABS LBRACE math RBRACE{ + /** @brief performs the abs(__) function + * @FN_ABS the symbol "abs" + * @LBRACE the symbol "(" + * function The target vector + * @RBRACE the symbol ")" + * return vector + */ + vec new_vec; + initialize_vector(&new_vec, NUMERIC, 1); + new_vec.content[0] = ABSV( + $3.content[0] + ); + $$ = new_vec; + free_vector($3); + } + | LBRACE math RBRACE{ $$ = $2; } | math MULT math{ - // Collapse both sides and subtract - vec vector1; - vec vector2; - vector1 = $1; - vector2 = $3; + /** @brief Collapse both sides and multiply + * Math vector + * MULT symbol '*' + * Math vector + */ + vec vector1 = $1; + vec vector2 = $3; if (vector1.dtype == SYMBOLIC || vector2.dtype == SYMBOLIC){ printf("Multiplication not implemented for symbolic dice.\n"); @@ -237,14 +319,20 @@ math: $$ = new_vec; } + + free_vector(vector1); + free_vector(vector2); } | math DIVIDE_ROUND_UP math{ + /** @brief Collapse both sides and divide + * Math vector + * Divide symbol '/' + * Math vector + */ // Collapse both sides and subtract - vec vector1; - vec vector2; - vector1 = $1; - vector2 = $3; + vec vector1 = $1; + vec vector2 = $3; if (vector1.dtype == SYMBOLIC || vector2.dtype == SYMBOLIC){ printf("Division unsupported for symbolic dice.\n"); @@ -270,14 +358,20 @@ math: $$ = new_vec; } + + free_vector(vector1); + free_vector(vector2); } | math DIVIDE_ROUND_DOWN math{ + /** @brief Collapse both sides and divide + * Math vector + * Divide symbol '\' + * Math vector + */ // Collapse both sides and subtract - vec vector1; - vec vector2; - vector1 = $1; - vector2 = $3; + vec vector1 = $1; + vec vector2 = $3; if (vector1.dtype == SYMBOLIC || vector2.dtype == SYMBOLIC){ printf("Division unsupported for symbolic dice.\n"); @@ -305,15 +399,20 @@ math: $$ = new_vec; } + + free_vector(vector1); + free_vector(vector2); } | math MODULO math{ + /** @brief Collapse both sides and modulo + * Math vector + * MULT symbol '%' + * Math vector + */ // Collapse both sides and subtract - vec vector1; - vec vector2; - - vector1 = $1; - vector2 = $3; + vec vector1 = $1; + vec vector2 = $3; if (vector1.dtype == SYMBOLIC || vector2.dtype == SYMBOLIC){ printf("Modulo unsupported for symbolic dice.\n"); @@ -337,14 +436,20 @@ math: $$ = new_vec; } + + free_vector(vector1); + free_vector(vector2); } | math PLUS math{ + /** @brief + * math vector + * PLUS symbol "+" + * math vector + */ // Collapse both sides and subtract - vec vector1; - vec vector2; - vector1 = $1; - vector2 = $3; + vec vector1 = $1; + vec vector2 = $3; if ( (vector1.dtype == SYMBOLIC && vector2.dtype == NUMERIC) || @@ -377,11 +482,7 @@ math: vector2.symbols, vector2.length, new_vec.symbols ); - // free(vector1.symbols); - // free(vector2.symbols); - $$ = new_vec; - }else{ int v1 = collapse(vector1.content, vector1.length); int v2 = collapse(vector2.content, vector2.length); @@ -398,14 +499,19 @@ math: $$ = new_vec; } + free_vector(vector1); + free_vector(vector2); } | math MINUS math{ - vec vector1; - vec vector2; - vector1 = $1; - vector2 = $3; + /** @brief Collapse both sides and subtract + * Math vector + * MINUS symbol '-' + * Math vector + */ + vec vector1 = $1; + vec vector2 = $3; if ( (vector1.dtype == SYMBOLIC || vector2.dtype == SYMBOLIC) ){ @@ -433,13 +539,18 @@ math: $$ = new_vec; } + free_vector(vector1); + free_vector(vector2); } | MINUS math %prec UMINUS{ + /** + * MINUS a symbol '-' + * math a vector + */ // Eltwise Negation - vec vector; - vector = $2; + vec vector = $2; if (vector.dtype == SYMBOLIC){ printf("Symbolic Dice, Cannot negate. Consider using Numeric dice or post-processing.\n"); @@ -463,6 +574,7 @@ math: $$ = new_vec; } + free_vector(vector); } | collapsing_dice_operations @@ -470,25 +582,31 @@ math: collapsing_dice_operations: dice_operations DO_COUNT{ + /** + * dice_operations - a vector + * DO_COUNT - a symbol 'c' + */ vec new_vec; vec dice = $1; initialize_vector(&new_vec, NUMERIC, 1); new_vec.content[0] = (int)dice.length; + free_vector(dice); $$ = new_vec; } | dice_operations{ + /** + * dice_operations a vector + * returns a vector + */ - vec vector; - vector = $1; + vec vector = $1; if (vector.dtype == SYMBOLIC){ // Symbolic, Impossible to collapse $$ = vector; - - } else{ // Collapse if Necessary @@ -496,27 +614,36 @@ collapsing_dice_operations: vec new_vector; initialize_vector(&new_vector, NUMERIC, 1); new_vector.content[0] = sum(vector.content, vector.length); - $$ = new_vector; + free_vector(vector); }else{ $$ = vector; } - } } ; dice_operations: - die_roll REROLL REROLL condition NUMBER{ + /** + * dice_roll a vector + * REROLL symbol 'r' + * REROLL symbol 'r' + * condition vector + * Number vector + * returns a vector + */ vec dice = $1; - int check = $4.content[0]; + vec cv = $4; + vec cvno = $5; + + int check = cv.content[0]; if(dice.dtype == NUMERIC){ int count = 0; - while (! check_condition(&dice, &$5, (COMPARATOR)check)){ + while (! check_condition(&dice, &cvno, (COMPARATOR)check)){ if (count > MAX_ITERATION){ printf("MAX ITERATION LIMIT EXCEEDED: REROLL\n"); gnoll_errno = MAX_LOOP_LIMIT_HIT; @@ -540,22 +667,36 @@ dice_operations: 1 ); count ++; + free_vector(die_sides); + free_vector(number_of_dice); } $$ = dice; + }else{ printf("No support for Symbolic die rerolling yet!\n"); gnoll_errno = NOT_IMPLEMENTED; YYABORT; yyclearin; } + free_vector(cv); + free_vector(cvno); } - |die_roll REROLL condition NUMBER{ + | + die_roll REROLL condition NUMBER{ + /* + * die_roll vector + * Reroll symbol + * condition vector + * Number vector + */ vec dice = $1; - int check = $3.content[0]; + vec comp = $3; + int check = comp.content[0]; + vec numv = $4; if(dice.dtype == NUMERIC){ - if (check_condition(&dice, &$4, (COMPARATOR)check)){ + if (check_condition(&dice, &numv, (COMPARATOR)check)){ vec number_of_dice; initialize_vector(&number_of_dice, NUMERIC, 1); @@ -572,9 +713,11 @@ dice_operations: dice.source.explode, 1 ); + free_vector(dice); + free_vector(number_of_dice); }else{ // No need to reroll - $$ = $1; + $$ = dice; } }else{ printf("No support for Symbolic die rerolling yet!"); @@ -582,13 +725,23 @@ dice_operations: YYABORT; yyclearin;; } + free_vector(numv); + free_vector(comp); } | dice_operations FILTER condition NUMBER{ + /* + * dice_operations vector + * Filter symbol 'f' + * condition vector + * Number vector + */ vec new_vec; vec dice = $1; vec condition = $4; - int check = $3.content[0]; + vec cv = $3; + + int check = cv.content[0]; if(dice.dtype == NUMERIC){ initialize_vector(&new_vec, NUMERIC, dice.length); @@ -599,15 +752,22 @@ dice_operations: printf("No support for Symbolic die rerolling yet!\n"); gnoll_errno = NOT_IMPLEMENTED; YYABORT; - yyclearin;; + yyclearin; } - + free_vector(dice); + free_vector(condition); + free_vector(cv); } | dice_operations FILTER singular_condition{ - vec new_vec; + /** + * dice_operations vector + * FILTER symbol 'f' + * singular_condition symbol + */ vec dice = $1; int check = $3.content[0]; + vec new_vec; if(dice.dtype == NUMERIC){ initialize_vector(&new_vec, NUMERIC, dice.length); @@ -620,11 +780,15 @@ dice_operations: YYABORT; yyclearin;; } + free_vector(dice); } | dice_operations UNIQUE{ - // TODO + /** + * dice_operations vector + * UNIQUE symbol 'u' + */ vec new_vec; vec dice = $1; @@ -639,65 +803,102 @@ dice_operations: YYABORT; yyclearin;; } + free_vector(dice); } | - dice_operations KEEP_HIGHEST NUMBER - { + dice_operations KEEP_HIGHEST NUMBER{ + /** + * dice_operations vector + * KEEP_HIGHEST symbol 'kh' + * NUMBER vector + */ + vec do_vec = $1; vec keep_vector = $3; vec new_vec; unsigned int num_to_hold = (unsigned int)keep_vector.content[0]; - keep_highest_values(&$1, &new_vec, num_to_hold); + keep_highest_values(&do_vec, &new_vec, num_to_hold); $$ = new_vec; + // free_vector(do_vec); + free_vector(keep_vector); } | - dice_operations DROP_HIGHEST NUMBER - { + dice_operations DROP_HIGHEST NUMBER{ + /** + * dice_operations vector + * KEEP_HIGHEST symbol 'kh' + * NUMBER vector + */ + vec do_vec = $1; vec keep_vector = $3; vec new_vec; unsigned int num_to_hold = (unsigned int)keep_vector.content[0]; - drop_highest_values(&$1, &new_vec, num_to_hold); + drop_highest_values(&do_vec, &new_vec, num_to_hold); $$ = new_vec; + // free_vector(do_vec); + free_vector(keep_vector); + } | - dice_operations KEEP_LOWEST NUMBER - { - vec keep_vector; - keep_vector = $3; + dice_operations KEEP_LOWEST NUMBER{ + /** + * dice_operations vector + * KEEP_HIGHEST symbol 'kh' + * NUMBER vector + */ + + vec do_vec = $1; + vec keep_vector = $3; unsigned int num_to_hold = (unsigned int)keep_vector.content[0]; vec new_vec; - keep_lowest_values(&$1, &new_vec, num_to_hold); + keep_lowest_values(&do_vec, &new_vec, num_to_hold); $$ = new_vec; + // free_vector(do_vec); + free_vector(keep_vector); } | - dice_operations DROP_LOWEST NUMBER - { - vec keep_vector; - keep_vector = $3; + dice_operations DROP_LOWEST NUMBER{ + /** + * dice_operations vector + * KEEP_HIGHEST symbol 'kh' + * NUMBER vector + */ + vec do_vec = $1; + vec keep_vector = $3; unsigned int num_to_hold = (unsigned int)keep_vector.content[0]; vec new_vec; - drop_lowest_values(&$1, &new_vec, num_to_hold); + drop_lowest_values(&do_vec, &new_vec, num_to_hold); $$ = new_vec; + // free_vector(do_vec); + free_vector(keep_vector); } | - dice_operations KEEP_HIGHEST - { + dice_operations KEEP_HIGHEST{ + /** + * dice_operations vector + * KEEP_HIGHEST symbol 'kh' + */ + vec do_vec = $1; unsigned int num_to_hold = 1; vec new_vec; - keep_highest_values(&$1, &new_vec, num_to_hold); + keep_highest_values(&do_vec, &new_vec, num_to_hold); $$ = new_vec; + // free_vector(do_vec); } | - dice_operations DROP_HIGHEST - { + dice_operations DROP_HIGHEST{ + /** + * dice_operations vector + * KEEP_HIGHEST symbol 'kh' + */ vec roll_vec = $1; unsigned int num_to_hold = 1; @@ -705,20 +906,29 @@ dice_operations: drop_highest_values(&roll_vec, &new_vec, num_to_hold); $$ = new_vec; + // free_vector(roll_vec); } | - dice_operations KEEP_LOWEST - { + dice_operations KEEP_LOWEST{ + /** + * dice_operations vector + * KEEP_LOWEST symbol 'kh' + */ + vec roll_vec = $1; unsigned int num_to_hold = 1; vec new_vec; - keep_lowest_values(&$1, &new_vec, num_to_hold); + keep_lowest_values(&roll_vec, &new_vec, num_to_hold); $$ = new_vec; + // free_vector(roll_vec); } | - dice_operations DROP_LOWEST - { + dice_operations DROP_LOWEST{ + /** + * dice_operations vector + * DROP_LOWEST symbol 'dl' + */ vec roll_vec = $1; unsigned int num_to_hold = 1; @@ -726,35 +936,55 @@ dice_operations: drop_lowest_values(&roll_vec, &new_vec, num_to_hold); $$ = new_vec; + // free_vector(roll_vec); } | die_roll - { - } ; die_roll: - NUMBER die_symbol NUMBER EXPLOSION ONCE - { - int start_from = $2.content[0]; + NUMBER die_symbol NUMBER EXPLOSION ONCE{ + /** + * NUMBER vector + * die_symbol vector + * NUMBER vector + * EXPLOSION symbol 'e' or similar + * ONCE symbol 'o' + */ + vec numA = $1; + vec ds = $2; + vec numB = $3; + + int start_from = ds.content[0]; vec number_of_dice; initialize_vector(&number_of_dice, NUMERIC, 1); number_of_dice.content[0] = 1; roll_plain_sided_dice( - &$1, - &$3, + &numA, + &numB, &$$, ONLY_ONCE_EXPLOSION, start_from ); + free_vector(numA); + free_vector(ds); + free_vector(numB); } | - die_symbol NUMBER EXPLOSION ONCE - { + die_symbol NUMBER EXPLOSION ONCE{ + /** + * die_symbol vector + * NUMBER vector + * EXPLOSION symbol 'e' or similar + * ONCE symbol 'o' + */ + + vec ds = $1; + vec numB = $2; - int start_from = $1.content[0]; + int start_from = ds.content[0]; vec number_of_dice; initialize_vector(&number_of_dice, NUMERIC, 1); @@ -762,34 +992,53 @@ die_roll: roll_plain_sided_dice( &number_of_dice, - &$2, + &numB, &$$, ONLY_ONCE_EXPLOSION, start_from ); + free_vector(number_of_dice); + free_vector(ds); + free_vector(numB); } | - NUMBER die_symbol NUMBER EXPLOSION PENETRATE - { - - int start_from = $2.content[0]; - - vec number_of_dice; - initialize_vector(&number_of_dice, NUMERIC, 1); - number_of_dice.content[0] = 1; + NUMBER die_symbol NUMBER EXPLOSION PENETRATE{ + /** + * NUMBER vector + * die_symbol vector + * NUMBER vector + * EXPLOSION symbol 'e' or similar + * PENETRATE symbol 'p' + */ + vec numA = $1; + vec ds = $2; + vec numB = $3; + int start_from = ds.content[0]; roll_plain_sided_dice( - &$1, - &$3, + &numA, + &numB, &$$, PENETRATING_EXPLOSION, start_from ); + + free_vector(numA); + free_vector(ds); + free_vector(numB); } | - die_symbol NUMBER EXPLOSION PENETRATE - { - int start_from = $1.content[0]; + die_symbol NUMBER EXPLOSION PENETRATE{ + /** + * die_symbol vector + * NUMBER vector + * EXPLOSION symbol 'e' or similar + * PENETRATE symbol 'p' + */ + vec ds = $1; + vec numB = $2; + + int start_from = ds.content[0]; vec number_of_dice; initialize_vector(&number_of_dice, NUMERIC, 1); @@ -797,35 +1046,51 @@ die_roll: roll_plain_sided_dice( &number_of_dice, - &$2, + &numB, &$$, PENETRATING_EXPLOSION, start_from ); + free_vector(number_of_dice); + free_vector(ds); + free_vector(numB); } | - NUMBER die_symbol NUMBER EXPLOSION - { - - int start_from = $2.content[0]; - - vec number_of_dice; - initialize_vector(&number_of_dice, NUMERIC, 1); - number_of_dice.content[0] = 1; + NUMBER die_symbol NUMBER EXPLOSION{ + /** + * NUMBER vector + * die_symbol vector + * NUMBER vector + * EXPLOSION symbol 'e' or similar + */ + + vec numA = $1; + vec ds = $2; + vec numB = $3; + int start_from = ds.content[0]; roll_plain_sided_dice( - &$1, - &$3, + &numA, + &numB, &$$, PENETRATING_EXPLOSION, start_from ); + free_vector(numA); + free_vector(ds); + free_vector(numB); } | - die_symbol NUMBER EXPLOSION - { + die_symbol NUMBER EXPLOSION{ + /** + * die_symbol vector + * NUMBER vector + * EXPLOSION symbol 'e' or similar + */ - int start_from = $1.content[0]; + vec ds = $1; + vec numB = $2; + int start_from = ds.content[0]; vec number_of_dice; initialize_vector(&number_of_dice, NUMERIC, 1); @@ -833,34 +1098,49 @@ die_roll: roll_plain_sided_dice( &number_of_dice, - &$2, + &numB, &$$, STANDARD_EXPLOSION, start_from ); + free_vector(numB); + free_vector(ds); + free_vector(number_of_dice); } | - NUMBER die_symbol NUMBER - { - int start_from = $2.content[0]; - - vec number_of_dice; - initialize_vector(&number_of_dice, NUMERIC, 1); - number_of_dice.content[0] = 1; + NUMBER die_symbol NUMBER{ + /** + * NUMBER vector + * die_symbol vector + * NUMBER vector + */ + vec numA = $1; + vec ds = $2; + vec numB = $3; + int start_from = ds.content[0]; roll_plain_sided_dice( - &$1, - &$3, + &numA, + &numB, &$$, NO_EXPLOSION, start_from ); + free_vector(numB); + free_vector(ds); + free_vector(numA); } | - die_symbol NUMBER - { + die_symbol NUMBER{ + /** + * die_symbol vector + * NUMBER vector + */ + vec ds = $1; + vec numB = $2; + vec new_vec; - int start_from = $1.content[0]; + int start_from = ds.content[0]; vec number_of_dice; initialize_vector(&number_of_dice, NUMERIC, 1); @@ -868,31 +1148,48 @@ die_roll: roll_plain_sided_dice( &number_of_dice, - &$2, - &$$, + &numB, + &new_vec, NO_EXPLOSION, start_from ); + free_vector(number_of_dice); + free_vector(ds); + free_vector(numB); + $$ = new_vec; } | - NUMBER die_symbol MODULO - { + NUMBER die_symbol MODULO{ + /** + * NUMBER vector + * die_symbol vector - d or z + * MODULE symbol % + */ + + // TODO: z% is not functional! + + vec num_dice = $1; vec dice_sides; initialize_vector(&dice_sides, NUMERIC, 1); dice_sides.content[0] = 100; roll_plain_sided_dice( - &$1, + &num_dice, &dice_sides, &$$, NO_EXPLOSION, 1 ); + free_vector(num_dice); + free_vector(dice_sides); } | - die_symbol MODULO - { - + die_symbol MODULO{ + /** + * die_symbol vector + * NUMBER vector + */ + // TODO: z% is not possible yet. vec num_dice; initialize_vector(&num_dice, NUMERIC, 1); num_dice.content[0] = 1; @@ -907,29 +1204,42 @@ die_roll: NO_EXPLOSION, 1 ); + free_vector(num_dice); + free_vector(dice_sides); } | - NUMBER die_symbol DO_COUNT - { - - int start_from = $2.content[0]; + NUMBER die_symbol DO_COUNT{ + /** + * NUMBER vector + * die_symbol vector + * DO_COUNT symbol 'c' + */ + vec num = $1; + vec die_sym = $2; + int start_from = die_sym.content[0]; vec dice_sides; initialize_vector(&dice_sides, NUMERIC, 1); dice_sides.content[0] = 2; roll_plain_sided_dice( - &$1, + &num, &dice_sides, &$$, NO_EXPLOSION, start_from ); + free_vector(num); + free_vector(die_sym); } | - die_symbol DO_COUNT - { - int start_from = $1.content[0]; + die_symbol DO_COUNT{ + /** + * die_symbol vector + * DO_COUNT symbol 'c' + */ + vec ds= $1; + int start_from = ds.content[0]; vec num_dice; initialize_vector(&num_dice, NUMERIC, 1); @@ -945,23 +1255,36 @@ die_roll: NO_EXPLOSION, start_from ); + free_vector(ds); + free_vector(num_dice); + free_vector(dice_sides); } | - NUMBER FATE_DIE - { + NUMBER FATE_DIE{ + /** + * NUMBER - + */ + vec number_of_dice = $1; + vec symb = $2; vec result_vec; - initialize_vector(&result_vec, SYMBOLIC, (unsigned int)$1.content[0]); + initialize_vector(&result_vec, SYMBOLIC, (unsigned int)number_of_dice.content[0]); roll_symbolic_dice( - &$1, - &$2, + &number_of_dice, + &symb, &result_vec ); $$ = result_vec; + free_vector(symb); + free_vector(number_of_dice); + } | - FATE_DIE - { + FATE_DIE{ + /** + * FATE_DIE - Vector + */ + vec symb = $1; vec result_vec; vec number_of_dice; initialize_vector(&result_vec, SYMBOLIC, 1); @@ -970,10 +1293,13 @@ die_roll: roll_symbolic_dice( &number_of_dice, - &$1, + &symb, &result_vec ); $$ = result_vec; + free_vector(symb); + free_vector(number_of_dice); + } | custom_symbol_dice @@ -981,36 +1307,55 @@ die_roll: NUMBER ; + custom_symbol_dice: NUMBER die_symbol SYMBOL_LBRACE csd SYMBOL_RBRACE { - + /** + * NUMBER - vector + * die_symbol - vector + * SYMBOL_LBRACE - the symbol { + * csd - vector + * SYMBOL_RBRACE - the symbol } + */ + // Nd{SYMB} vec left = $1; + vec dsymb = $2; vec right = $4; // TODO: Multiple ranges vec result_vec; - initialize_vector(&result_vec, SYMBOLIC, (unsigned int)$1.content[0]); + initialize_vector(&result_vec, SYMBOLIC, (unsigned int)left.content[0]); roll_symbolic_dice( &left, &right, &result_vec ); + + free_vector(left); + free_vector(right); + free_vector(dsymb); $$ = result_vec; } | die_symbol SYMBOL_LBRACE csd SYMBOL_RBRACE { - vec csd = $3; - vec result_vec; + /** @brief + * @param die_symbol a vector + * @param SYMBOL_LBRACE the symbol "{" + * @param csd a vector + * @param SYMBOL_LBRACE the symbol "}" + * returns a vector + */ + vec csd_vec = $3; vec number_of_dice; + vec result_vec; initialize_vector(&number_of_dice, NUMERIC, 1); number_of_dice.content[0] = 1; - - if (csd.dtype == NUMERIC){ + if (csd_vec.dtype == NUMERIC){ vec dice_sides; vec num_dice; initialize_vector(&dice_sides, NUMERIC, 1); @@ -1018,8 +1363,8 @@ custom_symbol_dice: initialize_vector(&result_vec, NUMERIC, 1); num_dice.content[0] = 1; - int start_value = csd.content[0]; - int end_value = csd.content[csd.length-1]; + int start_value = csd_vec.content[0]; + int end_value = csd_vec.content[csd_vec.length-1]; dice_sides.content[0] = end_value - start_value + 1; // Range @@ -1030,58 +1375,75 @@ custom_symbol_dice: NO_EXPLOSION, start_value ); - + free_vector(dice_sides); + free_vector(num_dice); }else{ initialize_vector(&result_vec, SYMBOLIC, 1); roll_params rp = { .number_of_dice=(unsigned int)number_of_dice.content[0], - .die_sides=csd.length, + .die_sides=csd_vec.length, .dtype=SYMBOLIC, .start_value=0, - .symbol_pool=(char **)safe_calloc(csd.length , sizeof(char *)) + .symbol_pool=(char **)safe_calloc(csd_vec.length , sizeof(char *)) }; - for(unsigned int i = 0; i != csd.length; i++){ - rp.symbol_pool[i] = malloc(MAX_SYMBOL_LENGTH); - memcpy(rp.symbol_pool[i], csd.symbols[i], MAX_SYMBOL_LENGTH*sizeof(char)); - // rp.symbol_pool[i] = csd.symbols[i]; - } result_vec.source = rp; + result_vec.has_source = true; + for(unsigned int i = 0; i != csd_vec.length; i++){ + result_vec.source.symbol_pool[i] = (char*)safe_calloc(sizeof(char),MAX_SYMBOL_LENGTH); + memcpy( + result_vec.source.symbol_pool[i], + csd_vec.symbols[i], + MAX_SYMBOL_LENGTH*sizeof(char) + ); + } // Custom Symbol roll_symbolic_dice( &number_of_dice, - &csd, + &csd_vec, &result_vec ); } + + free_vector(number_of_dice); + free_vector(csd_vec); + free_vector($1); $$ = result_vec; } | MACRO_ACCESSOR CAPITAL_STRING{ - vec vector; - vector = $2; + /** + * MACRO_ACCESSOR the symbol '@' + * CAPITAL_STRING A vector containing a macro identifier + * return A vector containing rollparams for the selected macro + */ + vec vector = $2; char * name = vector.symbols[0]; vec new_vector; search_macros(name, &new_vector.source); + if(gnoll_errno){YYABORT;yyclearin;} // Resolve Roll vec number_of_dice; + vec die_sides; + + // Set Num Dice initialize_vector(&number_of_dice, NUMERIC, 1); number_of_dice.content[0] = (int)new_vector.source.number_of_dice; + + // Set Die Sides + // die_sides.content[0] = (int)new_vector.source.die_sides; + // die_sides.symbols = NULL; - vec die_sides; - // TODO: Extract to function. - light_initialize_vector(&die_sides, NUMERIC, 1); - die_sides.content[0] = (int)new_vector.source.die_sides; - die_sides.length = new_vector.source.die_sides; - die_sides.symbols = NULL; - + // Roll according to the stored values + // Careful: Newvector used already if (new_vector.source.dtype == NUMERIC){ - // Careful, Newvector used already - + light_initialize_vector(&die_sides, NUMERIC, 1); + die_sides.length = new_vector.source.die_sides; + die_sides.content[0] = (int)new_vector.source.die_sides; initialize_vector(&new_vector, new_vector.source.dtype, 1); roll_plain_sided_dice( &number_of_dice, @@ -1090,8 +1452,12 @@ custom_symbol_dice: new_vector.source.explode, 1 ); + free_vector(die_sides); + }else if (new_vector.source.dtype == SYMBOLIC){ - free_2d_array(&die_sides.symbols, die_sides.length); + light_initialize_vector(&die_sides, SYMBOLIC, 1); + die_sides.length = new_vector.source.die_sides; + free(die_sides.symbols); safe_copy_2d_chararray_with_allocation( &die_sides.symbols, new_vector.source.symbol_pool, @@ -1099,27 +1465,35 @@ custom_symbol_dice: MAX_SYMBOL_LENGTH ); - // Careful, Newvector used already - initialize_vector(&new_vector, new_vector.source.dtype, 1); + free_2d_array(&new_vector.source.symbol_pool, new_vector.source.die_sides); + initialize_vector(&new_vector, new_vector.source.dtype, 1); roll_symbolic_dice( &number_of_dice, &die_sides, &new_vector ); + free_vector(die_sides); + }else{ printf("Complex Dice Equation. Only dice definitions supported. No operations\n"); gnoll_errno = NOT_IMPLEMENTED; } + free_vector(vector); + free_vector(number_of_dice); $$ = new_vector; } ; csd: csd SYMBOL_SEPERATOR csd{ - vec l; - vec r; - l = $1; - r = $3; + /** + * csd a vector containing custom symbols + * SYMBOL_SEPERATOR the symbol ',' + * csd a vector containing custom symbols + * return A vector with all the symbols + */ + vec l = $1; + vec r = $3; vec new_vector; initialize_vector(&new_vector, SYMBOLIC, l.length + r.length); @@ -1129,10 +1503,18 @@ csd: r.symbols, r.length, new_vector.symbols ); + free_vector(l); + free_vector(r); $$ = new_vector; } | NUMBER RANGE NUMBER{ + /** + * NUMBER The symbol 0-9+ + * RANGE The symbol '..' + * NUMBER The symbol 0-9+ + * return A vector containing the numeric values as symbols + */ vec start = $1; vec end = $3; @@ -1165,11 +1547,17 @@ csd: CAPITAL_STRING | NUMBER{ + /** + * NUMBER The symbol 0-9+ + * return A vector containing the numeric values as symbols + */ vec in = $1; - // Max/Min int has 10 characters + // INT_MAX/INT_MIN has 10 characters in.symbols = safe_calloc(1, sizeof(char *)); in.symbols[0] = safe_calloc(10, sizeof(char)); sprintf(in.symbols[0], "%d", in.content[0]); + free(in.content); + in.dtype = SYMBOLIC; $$ = in; } ; @@ -1179,6 +1567,10 @@ condition: EQ | LT | GT | LE | GE | NE ; die_symbol: SIDED_DIE{ + /** + * @brief SIDED_DIE The symbol 'd' + * @param return A vector containing '1', the start index + */ vec new_vec; initialize_vector(&new_vec, NUMERIC, 1); new_vec.content[0] = 1; @@ -1186,6 +1578,10 @@ die_symbol: } | SIDED_DIE_ZERO{ + /** + * SIDED_DIE The symbol 'z' + * return A vector containing '0', the start index + */ vec new_vec; initialize_vector(&new_vec, NUMERIC, 1); new_vec.content[0] = 0; @@ -1193,48 +1589,6 @@ die_symbol: } ; -function: - FN_MAX LBRACE function SYMBOL_SEPERATOR function RBRACE{ - vec new_vec; - initialize_vector(&new_vec, NUMERIC, 1); - int vmax = MAX( - $3.content[0], - $5.content[0] - ); - new_vec.content[0] = vmax; - $$ = new_vec; - free($3.content); - free($5.content); - } - | - FN_MIN LBRACE function SYMBOL_SEPERATOR function RBRACE{ - vec new_vec; - initialize_vector(&new_vec, NUMERIC, 1); - new_vec.content[0] = MIN( - $3.content[0], - $5.content[0] - ); - $$ = new_vec; - free($3.content); - free($5.content); - } - | - FN_ABS LBRACE function RBRACE{ - vec new_vec; - initialize_vector(&new_vec, NUMERIC, 1); - new_vec.content[0] = ABS( - $3.content[0] - ); - $$ = new_vec; - free($3.content); - } - | - /* FN_POOL LBRACE dice_statement SYMBOL_SEPERATOR dice_statement RBRACE{ - make_pool($2, $4); - } */ - | - math -; %% @@ -1250,7 +1604,7 @@ int roll_full_options( int enable_verbosity, int enable_introspection, int enable_mocking, - // int enable_builtins, + int enable_builtins, int mocking_type, int mocking_seed ){ @@ -1290,78 +1644,132 @@ int roll_full_options( } initialize(); - /* + if(enable_builtins){ load_builtins("builtins/"); } - */ + YY_BUFFER_STATE buffer = yy_scan_string(roll_request); yyparse(); yy_delete_buffer(buffer); + delete_all_macros(); + return gnoll_errno; } -/*void load_builtins(char* root){ +void load_builtins(char* root){ + + int db_setting = dice_breakdown; + dice_breakdown = 0; // Dont want dice breakdown for all the macro loading + + tinydir_dir dir = (tinydir_dir){0}; + tinydir_open(&dir, root); + + int count = 0; + while (dir.has_next) + { + tinydir_file file; + tinydir_readfile(&dir, &file); + if(verbose){ + printf("%s", file.name); + } + if (file.is_dir) + { + if(verbose){ + printf("/\n"); + } + }else{ + count++; + if(verbose){ + printf("\n"); + } + + unsigned long max_file_path_length = 1000; + int max_macro_length = 1000; + + char* path = safe_calloc(sizeof(char), max_file_path_length); + char* stored_str = safe_calloc(sizeof(char), (unsigned long)max_macro_length); + if(gnoll_errno){return;} + + // Get full path + strcat(path, "builtins/"); + strcat(path, file.name); + + // TODO: Check filename for length + FILE* fp = fopen(path, "r"); + while (fgets(stored_str, max_macro_length, fp)!=NULL); + + if(verbose){ + printf("Contents: %s\n",stored_str); + } + fclose(fp); + + YY_BUFFER_STATE buffer = yy_scan_string(stored_str); + yyparse(); + yy_delete_buffer(buffer); + if(gnoll_errno){return;} + + free(path); + free(stored_str); + } + tinydir_next(&dir); + } + + tinydir_close(&dir); + dice_breakdown = db_setting; return; -}*/ +} // The following are legacy functions to be deprecated in the future // in favor of the general roll_full_options() fn. int roll(char * s){ - return roll_full_options(s, NULL, 1, 0, 0, 0, 0); + return roll_full_options(s, NULL, 1, 0, 0, 0, 0, 0); } int roll_with_breakdown(char * s, char* f){ - return roll_full_options(s, f, 0, 1, 0, 0, 0); + return roll_full_options(s, f, 0, 1, 0, 0, 0, 0); } int roll_and_write(char* s, char* f){ - return roll_full_options(s, f, 0, 0, 0, 0, 0); + return roll_full_options(s, f, 0, 0, 0, 0, 0, 0); } void roll_and_write_R(int* return_code, char** s, char** f){ - (*return_code) = roll_full_options(s[0], f[0], 0, 0, 0, 0, 0); + (*return_code) = roll_full_options(s[0], f[0], 0, 0, 0, 0, 0, 0); } int mock_roll(char * s, char * f, int mock_value, int mock_const){ - return roll_full_options(s, f, 0, 0, 1, mock_value, mock_const); -} - -char * concat_strings(char ** s, int num_s){ - unsigned int size_total = 0; - int spaces = 0; - for(int i = 1; i != num_s + 1; i++){ - size_total += strlen(s[i]) + 1; - } - if (num_s > 1){ - spaces = 1; - size_total -= 1; // no need for trailing space - } - - char * result; - result = (char *)safe_calloc(sizeof(char), (size_total+1)); - if(gnoll_errno){return NULL;} - - for(int i = 1; i != num_s + 1; i++){ - strcat(result, s[i]); - if (spaces && i < num_s){ - strcat(result, " "); // Add spaces - } - } - return result; + return roll_full_options(s, f, 0, 0, 1, 0, mock_value, mock_const); } int main(int argc, char **str){ - char * s = concat_strings(str, argc - 1); - remove("output.dice"); + // Join arguments if they came in as seperate strings + char * s = concat_strings(&str[1], (unsigned int)(argc - 1)); - verbose = 1; - #ifdef BREAKDOWN - return roll_with_breakdown(s, "output.dice"); - #else - return roll(s); - #endif + remove("output.dice"); + roll_full_options( + s, + "output.dice", + 0, // Verbose + 0, // Introspect + 0, // Mocking + 1, // Builtins + 0, // Mocking + 0 // Mocking Seed + ); + print_gnoll_errors(); + FILE *f = fopen("output.dice","r"); + int c; + printf("Result:\n"); + if (f){ + while((c = getc(f)) != EOF){ + putchar(c); + } + fclose(f); + } + // Final Freeing + free(macros); } int yyerror(s) diff --git a/src/grammar/external/tinydir.h b/src/grammar/external/tinydir.h new file mode 100644 index 000000000..ba20c3e49 --- /dev/null +++ b/src/grammar/external/tinydir.h @@ -0,0 +1,838 @@ +/* +Copyright (c) 2013-2021, tinydir authors: +- Cong Xu +- Lautis Sun +- Baudouin Feildel +- Andargor +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef TINYDIR_H +#define TINYDIR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if ((defined _UNICODE) && !(defined UNICODE)) +#define UNICODE +#endif + +#if ((defined UNICODE) && !(defined _UNICODE)) +#define _UNICODE +#endif + +#include +#include +#include +#ifdef _MSC_VER +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +# pragma warning(push) +# pragma warning (disable : 4996) +#else +# include +# include +# include +# include +#endif +#ifdef __MINGW32__ +# include +#endif + + +/* types */ + +/* Windows UNICODE wide character support */ +#if defined _MSC_VER || defined __MINGW32__ +# define _tinydir_char_t TCHAR +# define TINYDIR_STRING(s) _TEXT(s) +# define _tinydir_strlen _tcslen +# define _tinydir_strcpy _tcscpy +# define _tinydir_strcat _tcscat +# define _tinydir_strcmp _tcscmp +# define _tinydir_strrchr _tcsrchr +# define _tinydir_strncmp _tcsncmp +#else +# define _tinydir_char_t char +# define TINYDIR_STRING(s) s +# define _tinydir_strlen strlen +# define _tinydir_strcpy strcpy +# define _tinydir_strcat strcat +# define _tinydir_strcmp strcmp +# define _tinydir_strrchr strrchr +# define _tinydir_strncmp strncmp +#endif + +#if (defined _MSC_VER || defined __MINGW32__) +# include +# define _TINYDIR_PATH_MAX MAX_PATH +#elif defined __linux__ +# include +# ifdef PATH_MAX +# define _TINYDIR_PATH_MAX PATH_MAX +# endif +#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +# include +# if defined(BSD) +# include +# ifdef PATH_MAX +# define _TINYDIR_PATH_MAX PATH_MAX +# endif +# endif +#endif + +#ifndef _TINYDIR_PATH_MAX +#define _TINYDIR_PATH_MAX 4096 +#endif + +#ifdef _MSC_VER +/* extra chars for the "\\*" mask */ +# define _TINYDIR_PATH_EXTRA 2 +#else +# define _TINYDIR_PATH_EXTRA 0 +#endif + +#define _TINYDIR_FILENAME_MAX 256 + +#if (defined _MSC_VER || defined __MINGW32__) +#define _TINYDIR_DRIVE_MAX 3 +#endif + +#ifdef _MSC_VER +# define _TINYDIR_FUNC static __inline +#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L +# define _TINYDIR_FUNC static __inline__ +#elif defined(__cplusplus) +# define _TINYDIR_FUNC static inline +#elif defined(__GNUC__) +/* Suppress unused function warning */ +# define _TINYDIR_FUNC __attribute__((unused)) static +#else +# define _TINYDIR_FUNC static +#endif + +/* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */ +#ifdef TINYDIR_USE_READDIR_R + +/* readdir_r is a POSIX-only function, and may not be available under various + * environments/settings, e.g. MinGW. Use readdir fallback */ +#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\ + _POSIX_SOURCE +# define _TINYDIR_HAS_READDIR_R +#endif +#if _POSIX_C_SOURCE >= 200112L +# define _TINYDIR_HAS_FPATHCONF +# include +#endif +#if _BSD_SOURCE || _SVID_SOURCE || \ + (_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700) +# define _TINYDIR_HAS_DIRFD +# include +#endif +#if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\ + defined _PC_NAME_MAX +# define _TINYDIR_USE_FPATHCONF +#endif +#if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\ + !(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX) +# define _TINYDIR_USE_READDIR +#endif + +/* Use readdir by default */ +#else +# define _TINYDIR_USE_READDIR +#endif + +/* MINGW32 has two versions of dirent, ASCII and UNICODE*/ +#ifndef _MSC_VER +#if (defined __MINGW32__) && (defined _UNICODE) +#define _TINYDIR_DIR _WDIR +#define _tinydir_dirent _wdirent +#define _tinydir_opendir _wopendir +#define _tinydir_readdir _wreaddir +#define _tinydir_closedir _wclosedir +#else +#define _TINYDIR_DIR DIR +#define _tinydir_dirent dirent +#define _tinydir_opendir opendir +#define _tinydir_readdir readdir +#define _tinydir_closedir closedir +#endif +#endif + +/* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */ +#if defined(_TINYDIR_MALLOC) && defined(_TINYDIR_FREE) +#elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE) +#else +#error "Either define both alloc and free or none of them!" +#endif + +#if !defined(_TINYDIR_MALLOC) + #define _TINYDIR_MALLOC(_size) malloc(_size) + #define _TINYDIR_FREE(_ptr) free(_ptr) +#endif /* !defined(_TINYDIR_MALLOC) */ + +typedef struct tinydir_file +{ + _tinydir_char_t path[_TINYDIR_PATH_MAX]; + _tinydir_char_t name[_TINYDIR_FILENAME_MAX]; + _tinydir_char_t *extension; + int is_dir; + int is_reg; + +#ifndef _MSC_VER +#ifdef __MINGW32__ + struct _stat _s; +#else + struct stat _s; +#endif +#endif +} tinydir_file; + +typedef struct tinydir_dir +{ + _tinydir_char_t path[_TINYDIR_PATH_MAX]; + int has_next; + size_t n_files; + + tinydir_file *_files; +#ifdef _MSC_VER + HANDLE _h; + WIN32_FIND_DATA _f; +#else + _TINYDIR_DIR *_d; + struct _tinydir_dirent *_e; +#ifndef _TINYDIR_USE_READDIR + struct _tinydir_dirent *_ep; +#endif +#endif +} tinydir_dir; + + +/* declarations */ + +_TINYDIR_FUNC +int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path); +_TINYDIR_FUNC +int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path); +_TINYDIR_FUNC +void tinydir_close(tinydir_dir *dir); + +_TINYDIR_FUNC +int tinydir_next(tinydir_dir *dir); +_TINYDIR_FUNC +int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file); +_TINYDIR_FUNC +int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i); +_TINYDIR_FUNC +int tinydir_open_subdir_n(tinydir_dir *dir, size_t i); + +_TINYDIR_FUNC +int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path); +_TINYDIR_FUNC +void _tinydir_get_ext(tinydir_file *file); +_TINYDIR_FUNC +int _tinydir_file_cmp(const void *a, const void *b); +#ifndef _MSC_VER +#ifndef _TINYDIR_USE_READDIR +_TINYDIR_FUNC +size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp); +#endif +#endif + + +/* definitions*/ + +_TINYDIR_FUNC +int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path) +{ +#ifndef _MSC_VER +#ifndef _TINYDIR_USE_READDIR + int error; + int size; /* using int size */ +#endif +#else + _tinydir_char_t path_buf[_TINYDIR_PATH_MAX]; +#endif + _tinydir_char_t *pathp; + + if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0) + { + errno = EINVAL; + return -1; + } + if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX) + { + errno = ENAMETOOLONG; + return -1; + } + + /* initialise dir */ + dir->_files = NULL; +#ifdef _MSC_VER + dir->_h = INVALID_HANDLE_VALUE; +#else + dir->_d = NULL; +#ifndef _TINYDIR_USE_READDIR + dir->_ep = NULL; +#endif +#endif + tinydir_close(dir); + + _tinydir_strcpy(dir->path, path); + /* Remove trailing slashes */ + pathp = &dir->path[_tinydir_strlen(dir->path) - 1]; + while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/'))) + { + *pathp = TINYDIR_STRING('\0'); + pathp++; + } +#ifdef _MSC_VER + _tinydir_strcpy(path_buf, dir->path); + _tinydir_strcat(path_buf, TINYDIR_STRING("\\*")); +#if (defined WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) + dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0); +#else + dir->_h = FindFirstFile(path_buf, &dir->_f); +#endif + if (dir->_h == INVALID_HANDLE_VALUE) + { + errno = ENOENT; +#else + dir->_d = _tinydir_opendir(path); + if (dir->_d == NULL) + { +#endif + goto bail; + } + + /* read first file */ + dir->has_next = 1; +#ifndef _MSC_VER +#ifdef _TINYDIR_USE_READDIR + dir->_e = _tinydir_readdir(dir->_d); +#else + /* allocate dirent buffer for readdir_r */ + size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */ + if (size == -1) return -1; + dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size); + if (dir->_ep == NULL) return -1; + + error = readdir_r(dir->_d, dir->_ep, &dir->_e); + if (error != 0) return -1; +#endif + if (dir->_e == NULL) + { + dir->has_next = 0; + } +#endif + + return 0; + +bail: + tinydir_close(dir); + return -1; +} + +_TINYDIR_FUNC +int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path) +{ + /* Count the number of files first, to pre-allocate the files array */ + size_t n_files = 0; + if (tinydir_open(dir, path) == -1) + { + return -1; + } + while (dir->has_next) + { + n_files++; + if (tinydir_next(dir) == -1) + { + goto bail; + } + } + tinydir_close(dir); + + if (n_files == 0 || tinydir_open(dir, path) == -1) + { + return -1; + } + + dir->n_files = 0; + dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files); + if (dir->_files == NULL) + { + goto bail; + } + while (dir->has_next) + { + tinydir_file *p_file; + dir->n_files++; + + p_file = &dir->_files[dir->n_files - 1]; + if (tinydir_readfile(dir, p_file) == -1) + { + goto bail; + } + + if (tinydir_next(dir) == -1) + { + goto bail; + } + + /* Just in case the number of files has changed between the first and + second reads, terminate without writing into unallocated memory */ + if (dir->n_files == n_files) + { + break; + } + } + + qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp); + + return 0; + +bail: + tinydir_close(dir); + return -1; +} + +_TINYDIR_FUNC +void tinydir_close(tinydir_dir *dir) +{ + if (dir == NULL) + { + return; + } + + memset(dir->path, 0, sizeof(dir->path)); + dir->has_next = 0; + dir->n_files = 0; + _TINYDIR_FREE(dir->_files); + dir->_files = NULL; +#ifdef _MSC_VER + if (dir->_h != INVALID_HANDLE_VALUE) + { + FindClose(dir->_h); + } + dir->_h = INVALID_HANDLE_VALUE; +#else + if (dir->_d) + { + _tinydir_closedir(dir->_d); + } + dir->_d = NULL; + dir->_e = NULL; +#ifndef _TINYDIR_USE_READDIR + _TINYDIR_FREE(dir->_ep); + dir->_ep = NULL; +#endif +#endif +} + +_TINYDIR_FUNC +int tinydir_next(tinydir_dir *dir) +{ + if (dir == NULL) + { + errno = EINVAL; + return -1; + } + if (!dir->has_next) + { + errno = ENOENT; + return -1; + } + +#ifdef _MSC_VER + if (FindNextFile(dir->_h, &dir->_f) == 0) +#else +#ifdef _TINYDIR_USE_READDIR + dir->_e = _tinydir_readdir(dir->_d); +#else + if (dir->_ep == NULL) + { + return -1; + } + if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0) + { + return -1; + } +#endif + if (dir->_e == NULL) +#endif + { + dir->has_next = 0; +#ifdef _MSC_VER + if (GetLastError() != ERROR_SUCCESS && + GetLastError() != ERROR_NO_MORE_FILES) + { + tinydir_close(dir); + errno = EIO; + return -1; + } +#endif + } + + return 0; +} + +_TINYDIR_FUNC +int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file) +{ + const _tinydir_char_t *filename; + if (dir == NULL || file == NULL) + { + errno = EINVAL; + return -1; + } +#ifdef _MSC_VER + if (dir->_h == INVALID_HANDLE_VALUE) +#else + if (dir->_e == NULL) +#endif + { + errno = ENOENT; + return -1; + } + filename = +#ifdef _MSC_VER + dir->_f.cFileName; +#else + dir->_e->d_name; +#endif + if (_tinydir_strlen(dir->path) + + _tinydir_strlen(filename) + 1 + _TINYDIR_PATH_EXTRA >= + _TINYDIR_PATH_MAX) + { + /* the path for the file will be too long */ + errno = ENAMETOOLONG; + return -1; + } + if (_tinydir_strlen(filename) >= _TINYDIR_FILENAME_MAX) + { + errno = ENAMETOOLONG; + return -1; + } + + _tinydir_strcpy(file->path, dir->path); + if (_tinydir_strcmp(dir->path, TINYDIR_STRING("/")) != 0) + _tinydir_strcat(file->path, TINYDIR_STRING("/")); + _tinydir_strcpy(file->name, filename); + _tinydir_strcat(file->path, filename); +#ifndef _MSC_VER +#ifdef __MINGW32__ + if (_tstat( +#elif (defined _BSD_SOURCE) || (defined _DEFAULT_SOURCE) \ + || ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) \ + || ((defined _POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + || ((defined __APPLE__) && (defined __MACH__)) \ + || (defined BSD) + if (lstat( +#else + if (stat( +#endif + file->path, &file->_s) == -1) + { + return -1; + } +#endif + _tinydir_get_ext(file); + + file->is_dir = +#ifdef _MSC_VER + !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); +#else + S_ISDIR(file->_s.st_mode); +#endif + file->is_reg = +#ifdef _MSC_VER + !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) || + ( + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) && + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) && +#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) && +#endif +#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) && +#endif + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) && + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY)); +#else + S_ISREG(file->_s.st_mode); +#endif + + return 0; +} + +_TINYDIR_FUNC +int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i) +{ + if (dir == NULL || file == NULL) + { + errno = EINVAL; + return -1; + } + if (i >= dir->n_files) + { + errno = ENOENT; + return -1; + } + + memcpy(file, &dir->_files[i], sizeof(tinydir_file)); + _tinydir_get_ext(file); + + return 0; +} + +_TINYDIR_FUNC +int tinydir_open_subdir_n(tinydir_dir *dir, size_t i) +{ + _tinydir_char_t path[_TINYDIR_PATH_MAX]; + if (dir == NULL) + { + errno = EINVAL; + return -1; + } + if (i >= dir->n_files || !dir->_files[i].is_dir) + { + errno = ENOENT; + return -1; + } + + _tinydir_strcpy(path, dir->_files[i].path); + tinydir_close(dir); + if (tinydir_open_sorted(dir, path) == -1) + { + return -1; + } + + return 0; +} + +/* Open a single file given its path */ +_TINYDIR_FUNC +int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path) +{ + tinydir_dir dir; + int result = 0; + int found = 0; + _tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX]; + _tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX]; + _tinydir_char_t *dir_name; + _tinydir_char_t *base_name; +#if (defined _MSC_VER || defined __MINGW32__) + _tinydir_char_t drive_buf[_TINYDIR_PATH_MAX]; + _tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX]; +#endif + + if (file == NULL || path == NULL || _tinydir_strlen(path) == 0) + { + errno = EINVAL; + return -1; + } + if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX) + { + errno = ENAMETOOLONG; + return -1; + } + + /* Get the parent path */ +#if (defined _MSC_VER || defined __MINGW32__) +#if ((defined _MSC_VER) && (_MSC_VER >= 1400)) + errno = _tsplitpath_s( + path, + drive_buf, _TINYDIR_DRIVE_MAX, + dir_name_buf, _TINYDIR_FILENAME_MAX, + file_name_buf, _TINYDIR_FILENAME_MAX, + ext_buf, _TINYDIR_FILENAME_MAX); +#else + _tsplitpath( + path, + drive_buf, + dir_name_buf, + file_name_buf, + ext_buf); +#endif + + if (errno) + { + return -1; + } + +/* _splitpath_s not work fine with only filename and widechar support */ +#ifdef _UNICODE + if (drive_buf[0] == L'\xFEFE') + drive_buf[0] = '\0'; + if (dir_name_buf[0] == L'\xFEFE') + dir_name_buf[0] = '\0'; +#endif + + /* Emulate the behavior of dirname by returning "." for dir name if it's + empty */ + if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0') + { + _tinydir_strcpy(dir_name_buf, TINYDIR_STRING(".")); + } + /* Concatenate the drive letter and dir name to form full dir name */ + _tinydir_strcat(drive_buf, dir_name_buf); + dir_name = drive_buf; + /* Concatenate the file name and extension to form base name */ + _tinydir_strcat(file_name_buf, ext_buf); + base_name = file_name_buf; +#else + _tinydir_strcpy(dir_name_buf, path); + dir_name = dirname(dir_name_buf); + _tinydir_strcpy(file_name_buf, path); + base_name = basename(file_name_buf); +#endif + + /* Special case: if the path is a root dir, open the parent dir as the file */ +#if (defined _MSC_VER || defined __MINGW32__) + if (_tinydir_strlen(base_name) == 0) +#else + if ((_tinydir_strcmp(base_name, TINYDIR_STRING("/"))) == 0) +#endif + { + memset(file, 0, sizeof * file); + file->is_dir = 1; + file->is_reg = 0; + _tinydir_strcpy(file->path, dir_name); + file->extension = file->path + _tinydir_strlen(file->path); + return 0; + } + + /* Open the parent directory */ + if (tinydir_open(&dir, dir_name) == -1) + { + return -1; + } + + /* Read through the parent directory and look for the file */ + while (dir.has_next) + { + if (tinydir_readfile(&dir, file) == -1) + { + result = -1; + goto bail; + } + if (_tinydir_strcmp(file->name, base_name) == 0) + { + /* File found */ + found = 1; + break; + } + tinydir_next(&dir); + } + if (!found) + { + result = -1; + errno = ENOENT; + } + +bail: + tinydir_close(&dir); + return result; +} + +_TINYDIR_FUNC +void _tinydir_get_ext(tinydir_file *file) +{ + _tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.')); + if (period == NULL) + { + file->extension = &(file->name[_tinydir_strlen(file->name)]); + } + else + { + file->extension = period + 1; + } +} + +_TINYDIR_FUNC +int _tinydir_file_cmp(const void *a, const void *b) +{ + const tinydir_file *fa = (const tinydir_file *)a; + const tinydir_file *fb = (const tinydir_file *)b; + if (fa->is_dir != fb->is_dir) + { + return -(fa->is_dir - fb->is_dir); + } + return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX); +} + +#ifndef _MSC_VER +#ifndef _TINYDIR_USE_READDIR +/* +The following authored by Ben Hutchings +from https://womble.decadent.org.uk/readdir_r-advisory.html +*/ +/* Calculate the required buffer size (in bytes) for directory * +* entries read from the given directory handle. Return -1 if this * +* this cannot be done. * +* * +* This code does not trust values of NAME_MAX that are less than * +* 255, since some systems (including at least HP-UX) incorrectly * +* define it to be a smaller value. */ +_TINYDIR_FUNC +size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp) +{ + long name_max; + size_t name_end; + /* parameter may be unused */ + (void)dirp; + +#if defined _TINYDIR_USE_FPATHCONF + name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX); + if (name_max == -1) +#if defined(NAME_MAX) + name_max = (NAME_MAX > 255) ? NAME_MAX : 255; +#else + return (size_t)(-1); +#endif +#elif defined(NAME_MAX) + name_max = (NAME_MAX > 255) ? NAME_MAX : 255; +#else +#error "buffer size for readdir_r cannot be determined" +#endif + name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1; + return (name_end > sizeof(struct _tinydir_dirent) ? + name_end : sizeof(struct _tinydir_dirent)); +} +#endif +#endif + +#ifdef __cplusplus +} +#endif + +# if defined (_MSC_VER) +# pragma warning(pop) +# endif + +#endif diff --git a/src/grammar/operations/condition_checking.c b/src/grammar/operations/conditionals.c similarity index 92% rename from src/grammar/operations/condition_checking.c rename to src/grammar/operations/conditionals.c index 3db17a98d..cb3607ba5 100644 --- a/src/grammar/operations/condition_checking.c +++ b/src/grammar/operations/conditionals.c @@ -1,106 +1,106 @@ -#include "condition_checking.h" - -#include -#include -#include - -#include "rolls/dice_logic.h" -#include "shared_header.h" -#include "util/safe_functions.h" -#include "util/vector_functions.h" -#include "yacc_header.h" - -extern int gnoll_errno; - -/** - * @brief Comparision of a collapsed vector to a value - * - * @param x vector containing dice rolls - * @param y vector containing 1 comparision value - * @param c enum indicating comparsion type - * @return true - the condition is True - * @return false - the condition is False - */ -int check_condition(vec* x, vec* y, COMPARATOR c) { - if (gnoll_errno) return 1; - - if(c == IS_UNIQUE || c == IF_ODD || c == IF_EVEN){ - return check_condition_vector(x, c); - }else{ - - int xvalue = collapse(x->content, x->length); - int yvalue = y->content[0]; - return check_condition_scalar(xvalue, yvalue, c); - } -} - -int check_condition_vector(vec* v, COMPARATOR c) { - switch (c){ - case IS_UNIQUE: { - gnoll_errno = NOT_IMPLEMENTED; - return 1; - } - case IF_EVEN:{ - int x = collapse(v->content, v->length); - return (x+1) % 2; - } - case IF_ODD: { - int x = collapse(v->content, v->length); - return x % 2; - } - default: { - gnoll_errno = NOT_IMPLEMENTED; - return 0; - } - } -} - -int check_condition_scalar(int x, int y, COMPARATOR c) { - if (gnoll_errno) return 1; - - int xvalue = x; - int yvalue = y; - switch (c) { - case EQUALS: { - return xvalue == yvalue; - } - case NOT_EQUAL: { - return xvalue != yvalue; - } - case LESS_THAN: { - return xvalue < yvalue; - } - case GREATER_THAN: { - return xvalue > yvalue; - } - case LESS_OR_EQUALS: { - return xvalue <= yvalue; - } - case GREATER_OR_EQUALS: { - return xvalue >= yvalue; - } - case IS_UNIQUE: { - // Unique by the fact that it is scalar - return 1; - } - case IF_ODD: { - return x % 2; - } - case IF_EVEN: { - return (x+1) % 2; - } - case INVALID: { - printf("Invalid Conditional\n"); - gnoll_errno = UNDEFINED_BEHAVIOUR; - return 0; - } - default: { - printf("Unknown Conditional\n"); - gnoll_errno = UNDEFINED_BEHAVIOUR; - return 0; - } - } - printf("Unknown Conditional\n"); - gnoll_errno = UNDEFINED_BEHAVIOUR; - return 1; -} +#include "conditionals.h" + +#include +#include +#include + +#include "rolls/dice_core.h" +#include "shared_header.h" +#include "util/safe_functions.h" +#include "util/vector_functions.h" +#include "util/array_functions.h" + +extern int gnoll_errno; + +/** + * @brief Comparision of a collapsed vector to a value + * + * @param x vector containing dice rolls + * @param y vector containing 1 comparision value + * @param c enum indicating comparsion type + * @return true - the condition is True + * @return false - the condition is False + */ +int check_condition(vec* x, vec* y, COMPARATOR c) { + if (gnoll_errno) return 1; + + if(c == IS_UNIQUE || c == IF_ODD || c == IF_EVEN){ + return check_condition_vector(x, c); + }else{ + + int xvalue = collapse(x->content, x->length); + int yvalue = y->content[0]; + return check_condition_scalar(xvalue, yvalue, c); + } +} + +int check_condition_vector(vec* v, COMPARATOR c) { + switch (c){ + case IS_UNIQUE: { + gnoll_errno = NOT_IMPLEMENTED; + return 1; + } + case IF_EVEN:{ + int x = collapse(v->content, v->length); + return (x+1) % 2; + } + case IF_ODD: { + int x = collapse(v->content, v->length); + return x % 2; + } + default: { + gnoll_errno = NOT_IMPLEMENTED; + return 0; + } + } +} + +int check_condition_scalar(int x, int y, COMPARATOR c) { + if (gnoll_errno) return 1; + + int xvalue = x; + int yvalue = y; + switch (c) { + case EQUALS: { + return xvalue == yvalue; + } + case NOT_EQUAL: { + return xvalue != yvalue; + } + case LESS_THAN: { + return xvalue < yvalue; + } + case GREATER_THAN: { + return xvalue > yvalue; + } + case LESS_OR_EQUALS: { + return xvalue <= yvalue; + } + case GREATER_OR_EQUALS: { + return xvalue >= yvalue; + } + case IS_UNIQUE: { + // Unique by the fact that it is scalar + return 1; + } + case IF_ODD: { + return x % 2; + } + case IF_EVEN: { + return (x+1) % 2; + } + case INVALID: { + printf("Invalid Conditional\n"); + gnoll_errno = UNDEFINED_BEHAVIOUR; + return 0; + } + default: { + printf("Unknown Conditional\n"); + gnoll_errno = UNDEFINED_BEHAVIOUR; + return 0; + } + } + printf("Unknown Conditional\n"); + gnoll_errno = UNDEFINED_BEHAVIOUR; + return 1; +} diff --git a/src/grammar/operations/condition_checking.h b/src/grammar/operations/conditionals.h similarity index 90% rename from src/grammar/operations/condition_checking.h rename to src/grammar/operations/conditionals.h index 5534ffed0..a571aa15b 100644 --- a/src/grammar/operations/condition_checking.h +++ b/src/grammar/operations/conditionals.h @@ -1,24 +1,24 @@ - -#ifndef __ROLL_CONDITION_CHECKING_H__ -#define __ROLL_CONDITION_CHECKING_H__ - -#include "rolls/vec.h" - -typedef enum { - INVALID = 0, - EQUALS = 1, - GREATER_THAN = 2, - LESS_THAN = 3, - GREATER_OR_EQUALS = 4, - LESS_OR_EQUALS = 5, - NOT_EQUAL = 6, - IS_UNIQUE = 7, - IF_EVEN = 8, - IF_ODD = 9, -} COMPARATOR; - -int check_condition(vec* x, vec* y, COMPARATOR c); - -int check_condition_scalar(int x, int y, COMPARATOR c); -int check_condition_vector(vec* v, COMPARATOR c); -#endif + +#ifndef __ROLL_CONDITION_CHECKING_H__ +#define __ROLL_CONDITION_CHECKING_H__ + +#include "constructs/vec.h" + +typedef enum { + INVALID = 0, + EQUALS = 1, + GREATER_THAN = 2, + LESS_THAN = 3, + GREATER_OR_EQUALS = 4, + LESS_OR_EQUALS = 5, + NOT_EQUAL = 6, + IS_UNIQUE = 7, + IF_EVEN = 8, + IF_ODD = 9, +} COMPARATOR; + +int check_condition(vec* x, vec* y, COMPARATOR c); + +int check_condition_scalar(int x, int y, COMPARATOR c); +int check_condition_vector(vec* v, COMPARATOR c); +#endif diff --git a/src/grammar/operations/macro_logic.c b/src/grammar/operations/macros.c similarity index 59% rename from src/grammar/operations/macro_logic.c rename to src/grammar/operations/macros.c index 96a78a807..01045d1a0 100644 --- a/src/grammar/operations/macro_logic.c +++ b/src/grammar/operations/macros.c @@ -1,117 +1,144 @@ - -#include "operations/macro_logic.h" - -#include "external/uthash.h" -#include "shared_header.h" -#include "util/safe_functions.h" -#include "util/vector_functions.h" -#include "yacc_header.h" - -// Initialized to NULL (Important) -struct macro_struct *macros = NULL; - -extern int gnoll_errno; - -unsigned long hash_function(unsigned char *str) { - /** - * @brief DJB2 hashing algorithm from http://www.cse.yorku.ca/~oz/hash.html - * - * @param str string to encode - * @return numeric hash encoding - */ - - unsigned long hash = 5381; - int c; - - while ((c = *str++)) { - hash = ((hash << 5) + hash) + (unsigned int)c; /* hash * 33 + c */ - } - return hash; -} - -void register_macro(vec *macro_name, roll_params *to_store) { - /** - * @brief Register a Macro in GNOLL - * - * @param macro_name - Unique name for macro reference - * @param to_store - Structure containing information on how to roll the dice - * referenced to by the key - */ - - if (gnoll_errno) { - return; - } - - char *skey = macro_name->symbols[0]; - unsigned long key = hash_function((unsigned char *)skey); - int k = (int)key; - if (gnoll_errno) { - return; - } - - struct macro_struct *s; - - unsigned short int is_symbolic = to_store->dtype == SYMBOLIC; - - HASH_FIND_INT(macros, &k, s); /* id already in the hash? */ - if (s == NULL) { - s = (struct macro_struct *)safe_malloc(sizeof *s); - - if (gnoll_errno) { - return; - } - s->id = (int)key; - HASH_ADD_INT(macros, id, s); /* id: name of key field */ - } - - memcpy(&s->stored_dice_roll, to_store, sizeof(*to_store)); - s->stored_dice_roll.symbol_pool = NULL; - - if (is_symbolic) { - free_2d_array(&s->stored_dice_roll.symbol_pool, - s->stored_dice_roll.die_sides); - safe_copy_2d_chararray_with_allocation( - &s->stored_dice_roll.symbol_pool, to_store->symbol_pool, - to_store->die_sides, MAX_SYMBOL_LENGTH); - } -} - -void search_macros(char *skey, roll_params *to_store) { - /** - * @brief Search for a registered macro - * - * @param macro_name - Unique name for macro reference - * @param to_store - Where to store the macro, if found - */ - if (gnoll_errno) { - return; - } - - unsigned long key = hash_function((unsigned char *)skey); - int k = (int)key; - - if (gnoll_errno) { - return; - } - - struct macro_struct *s; - - HASH_FIND_INT(macros, &k, s); /* s: output pointer */ - - if (s == NULL) { - gnoll_errno = UNDEFINED_MACRO; - return; - } - - *to_store = s->stored_dice_roll; - to_store->symbol_pool = NULL; - - unsigned short int is_symbolic = to_store->dtype == SYMBOLIC; - - if (is_symbolic) { - free_2d_array(&to_store->symbol_pool, to_store->die_sides); - safe_copy_2d_chararray_with_allocation( - &to_store->symbol_pool, s->stored_dice_roll.symbol_pool, - to_store->die_sides, MAX_SYMBOL_LENGTH); - } -} + +#include "operations/macros.h" + +#include "external/uthash.h" +#include "shared_header.h" +#include "util/safe_functions.h" +#include "util/vector_functions.h" +#include "shared_header.h" + +extern int verbose; + +// Initialized to NULL (Important) +struct macro_struct *macros = NULL; + +extern int gnoll_errno; + +unsigned long hash_function(unsigned char *str) { + /** + * @brief DJB2 hashing algorithm from http://www.cse.yorku.ca/~oz/hash.html + * + * @param str string to encode + * @return numeric hash encoding + */ + + unsigned long hash = 5381; + int c; + + while ((c = *str++)) { + hash = ((hash << 5) + hash) + (unsigned int)c; /* hash * 33 + c */ + } + return hash; +} + +void delete_all_macros() { + struct macro_struct *current_macro, *tmp; + + HASH_ITER(hh, macros, current_macro, tmp) { + HASH_DEL(macros, current_macro); /* delete; users advances to next */ + + if (current_macro->stored_dice_roll.dtype == SYMBOLIC){ + free_2d_array( + ¤t_macro->stored_dice_roll.symbol_pool, + current_macro->stored_dice_roll.die_sides + ); + } + free(current_macro); /* optional- if you want to free */ + } +} + +void register_macro(vec *macro_name, roll_params *to_store) { + /** + * @brief Register a Macro in GNOLL + * + * @param macro_name - Unique name for macro reference + * @param to_store - Structure containing information on how to roll the dice + * referenced to by the key + */ + + if (gnoll_errno) {return;} + + struct macro_struct *s; + char *skey = macro_name->symbols[0]; + + if (verbose) printf("Macro:: Get ID\n"); + unsigned long key = hash_function((unsigned char *)skey); + int k = (int)key; + + unsigned short int is_symbolic = to_store->dtype == SYMBOLIC; + + if (verbose) printf("Macro:: Check existance of %i\n", k); + HASH_FIND_INT(macros, &k, s); // id already in the hash? + if (s == NULL) { + s = (struct macro_struct *)safe_malloc(sizeof *s); + + if (gnoll_errno) { + return; + } + s->id = (int)key; + HASH_ADD_INT(macros, id, s); // id: name of key field + + memcpy(&s->stored_dice_roll, to_store, sizeof(*to_store)); + + if (is_symbolic) { + safe_copy_2d_chararray_with_allocation( + &s->stored_dice_roll.symbol_pool, to_store->symbol_pool, + to_store->die_sides, MAX_SYMBOL_LENGTH); + } + }else{ + if(verbose){printf("Already Exists\n");} + } +} + +void search_macros(char *skey, roll_params *to_store) { + /** + * @brief Search for a registered macro + * + * @param macro_name - Unique name for macro reference + * @param to_store - Where to store the macro, if found + */ + if (gnoll_errno) { + return; + } + + unsigned long key = hash_function((unsigned char *)skey); + int k = (int)key; + + if (gnoll_errno) { + return; + } + + struct macro_struct *s; + + HASH_FIND_INT(macros, &k, s); /* s: output pointer */ + + + if (s == NULL) { + if (verbose) printf("Macro:: UNDEFINED (macros.c)\n"); + gnoll_errno = UNDEFINED_MACRO; + return; + } + + *to_store = s->stored_dice_roll; + to_store->symbol_pool = NULL; + // free_2d_array(&to_store->symbol_pool, to_store->die_sides); + + unsigned short int is_symbolic = to_store->dtype == SYMBOLIC; + + if (is_symbolic) { + free_2d_array(&to_store->symbol_pool, to_store->die_sides); + safe_copy_2d_chararray_with_allocation( + &to_store->symbol_pool, + s->stored_dice_roll.symbol_pool, + to_store->die_sides, + MAX_SYMBOL_LENGTH + ); + + } + /* DO NOT UNCOMMENT. + We need to keep 's' + Otherwise macros are lost after usage + free(s); + */ + +} diff --git a/src/grammar/operations/macro_logic.h b/src/grammar/operations/macros.h similarity index 86% rename from src/grammar/operations/macro_logic.h rename to src/grammar/operations/macros.h index fb3fe8c77..f09c3d12b 100644 --- a/src/grammar/operations/macro_logic.h +++ b/src/grammar/operations/macros.h @@ -1,21 +1,23 @@ - -#ifndef __MACRO_LOGIC_H -#define __MACRO_LOGIC_H - -#include "external/uthash.h" -#include "rolls/dice_roll_structs.h" -#include "util/vector_functions.h" - -unsigned long hash_function(unsigned char *str); - -struct macro_struct { - int id; /* key */ - roll_params stored_dice_roll; - UT_hash_handle hh; /* makes this structure hashable */ -}; - -void register_macro(vec *macro_name, roll_params *to_store); - -void search_macros(char *skey, roll_params *to_store); - -#endif + +#ifndef __MACRO_LOGIC_H +#define __MACRO_LOGIC_H + +#include "external/uthash.h" +#include "constructs/roll_parameters.h" +#include "util/vector_functions.h" + +unsigned long hash_function(unsigned char *str); + +struct macro_struct { + int id; /* key */ + roll_params stored_dice_roll; + UT_hash_handle hh; /* makes this structure hashable */ +}; + +void delete_all_macros(); + +void register_macro(vec *macro_name, roll_params *to_store); + +void search_macros(char *skey, roll_params *to_store); + +#endif diff --git a/src/grammar/rolls/dice_logic.c b/src/grammar/rolls/dice_core.c similarity index 96% rename from src/grammar/rolls/dice_logic.c rename to src/grammar/rolls/dice_core.c index 2e4cb7464..7194620ab 100644 --- a/src/grammar/rolls/dice_logic.c +++ b/src/grammar/rolls/dice_core.c @@ -1,4 +1,4 @@ -#include "rolls/dice_logic.h" +#include "rolls/dice_core.h" #include #include @@ -6,11 +6,11 @@ #include #include "external/pcg_basic.h" -#include "rolls/dice_enums.h" -#include "rolls/mocking.h" +#include "constructs/dice_enums.h" +#include "util/mocking.h" #include "shared_header.h" #include "util/safe_functions.h" -#include "yacc_header.h" +#include "shared_header.h" #if USE_SECURE_RANDOM == 1 #include @@ -137,7 +137,6 @@ int* perform_roll(unsigned int number_of_dice, unsigned int die_sides, fprintf(fp, "\n"); fclose(fp); } - return all_dice_roll; } diff --git a/src/grammar/rolls/dice_logic.h b/src/grammar/rolls/dice_core.h similarity index 92% rename from src/grammar/rolls/dice_logic.h rename to src/grammar/rolls/dice_core.h index cb428fde1..883fa6582 100644 --- a/src/grammar/rolls/dice_logic.h +++ b/src/grammar/rolls/dice_core.h @@ -1,7 +1,7 @@ #ifndef __DIE_LOGIC_H__ #define __DIE_LOGIC_H__ -#include "rolls/dice_enums.h" +#include "constructs/dice_enums.h" #include "shared_header.h" // #ifdef __cplusplus diff --git a/src/grammar/rolls/sided_dice.c b/src/grammar/rolls/dice_frontend.c similarity index 85% rename from src/grammar/rolls/sided_dice.c rename to src/grammar/rolls/dice_frontend.c index 57e697a41..2c3fcdf54 100644 --- a/src/grammar/rolls/sided_dice.c +++ b/src/grammar/rolls/dice_frontend.c @@ -1,72 +1,81 @@ -#include -#include -#include -#include - -#include "rolls/dice_logic.h" -#include "shared_header.h" -#include "util/safe_functions.h" -#include "util/vector_functions.h" -#include "yacc_header.h" - -extern int gnoll_errno; - -void roll_plain_sided_dice(vec* x, vec* y, vec* result, EXPLOSION_TYPE explode, - int start_offset) { - /** - * @brief Roll numeric dice - * @param x - Amount of dice (xDy) - * @param y - Dice Sides (xDy) - * @param result - Where to store the dice roll result - * @param explode Explosion logic to apply (if applicable) - * @param start_offset offset each dice roll by this amount - */ - if (gnoll_errno) return; - - // XdY - unsigned int num_dice = (unsigned int)x->content[0]; - unsigned int sides = (unsigned int)y->content[0]; - - // e.g. d4, it is implied that it is a single dice - roll_params rp; - rp.dtype = NUMERIC; - rp.number_of_dice = num_dice; - rp.die_sides = sides; - rp.explode = explode; - rp.start_value = start_offset; - int* roll_result = do_roll(rp); - initialize_vector(result, NUMERIC, num_dice); - result->content = roll_result; - result->source = rp; -} - -void roll_symbolic_dice(vec* x, vec* y, vec* result) { - /** - * @brief Roll symbolic dice - * @param x - Amount of dice (xDy) - * @param y - Dice Sides (xDy) - * @param result - Where to store the dice roll result - */ - if (gnoll_errno) return; - - unsigned int num_dice = (unsigned int)x->content[0]; - - // e.g. d4, it is implied that it is a single dice - roll_params rp; - rp.dtype = SYMBOLIC; - rp.number_of_dice = num_dice; - rp.die_sides = y->length; - rp.explode = (EXPLOSION_TYPE)0; - rp.symbol_pool = NULL; - - // Copy over memory to Symbol Pool for reloading - - free_2d_array(&rp.symbol_pool, rp.die_sides); - safe_copy_2d_chararray_with_allocation(&rp.symbol_pool, y->symbols, y->length, - MAX_SYMBOL_LENGTH); - rp.start_value = 0; // First index of array - - int* indexes = do_roll(rp); - - extract_symbols(y->symbols, result->symbols, indexes, rp.number_of_dice); -} +#include +#include +#include +#include + +#include "rolls/dice_core.h" +#include "shared_header.h" +#include "util/safe_functions.h" +#include "util/vector_functions.h" +#include "shared_header.h" + +extern int gnoll_errno; + +void roll_plain_sided_dice(vec* x, vec* y, vec* result, EXPLOSION_TYPE explode, + int start_offset) { + /** + * @brief Roll numeric dice + * @param x - Amount of dice (xDy) + * @param y - Dice Sides (xDy) + * @param result - Where to store the dice roll result + * @param explode Explosion logic to apply (if applicable) + * @param start_offset offset each dice roll by this amount + */ + if (gnoll_errno) return; + + // XdY + unsigned int num_dice = (unsigned int)x->content[0]; + unsigned int sides = (unsigned int)y->content[0]; + + // e.g. d4, it is implied that it is a single dice + roll_params rp; + rp.dtype = NUMERIC; + rp.number_of_dice = num_dice; + rp.die_sides = sides; + rp.explode = explode; + rp.start_value = start_offset; + int* roll_result = do_roll(rp); + + initialize_vector(result, NUMERIC, num_dice); + free(result->content); + result->content = roll_result; + result->source = rp; + result->has_source = true; +} + +void roll_symbolic_dice(vec* x, vec* y, vec* result) { + /** + * @brief Roll symbolic dice + * @param x - Amount of dice (xDy) + * @param y - Dice Sides (xDy) + * @param result - Where to store the dice roll result + */ + if (gnoll_errno) return; + + unsigned int num_dice = (unsigned int)x->content[0]; + + // e.g. d4, it is implied that it is a single dice + roll_params rp; + rp.dtype = SYMBOLIC; + rp.number_of_dice = num_dice; + rp.die_sides = y->length; + rp.explode = (EXPLOSION_TYPE)0; + rp.symbol_pool = NULL; + + // Copy over memory to Symbol Pool for reloading + safe_copy_2d_chararray_with_allocation( + &rp.symbol_pool, + y->symbols, + y->length, + MAX_SYMBOL_LENGTH + ); + + rp.start_value = 0; // First index of array + + int* indexes = do_roll(rp); + + free_2d_array(&rp.symbol_pool, y->length); + + extract_symbols(y->symbols, result->symbols, indexes, rp.number_of_dice); + free(indexes); +} diff --git a/src/grammar/rolls/sided_dice.h b/src/grammar/rolls/dice_frontend.h similarity index 82% rename from src/grammar/rolls/sided_dice.h rename to src/grammar/rolls/dice_frontend.h index c93401e99..d2cd01f3a 100644 --- a/src/grammar/rolls/sided_dice.h +++ b/src/grammar/rolls/dice_frontend.h @@ -1,14 +1,14 @@ - -#ifndef __ROLL_SIDED_DICE_H__ -#define __ROLL_SIDED_DICE_H__ - -#include "../util/vector_functions.h" -#include "dice_enums.h" -#include "vec.h" - -void roll_plain_sided_dice(vec* x, vec* y, vec* result, EXPLOSION_TYPE explode, - int start_offset); - -void roll_symbolic_dice(vec* x, vec* y, vec* result); - -#endif + +#ifndef __ROLL_SIDED_DICE_H__ +#define __ROLL_SIDED_DICE_H__ + +#include "../util/vector_functions.h" +#include "constructs/dice_enums.h" +#include "constructs/vec.h" + +void roll_plain_sided_dice(vec* x, vec* y, vec* result, EXPLOSION_TYPE explode, + int start_offset); + +void roll_symbolic_dice(vec* x, vec* y, vec* result); + +#endif diff --git a/src/grammar/shared_header.h b/src/grammar/shared_header.h index 0a0747420..a2d095812 100644 --- a/src/grammar/shared_header.h +++ b/src/grammar/shared_header.h @@ -6,15 +6,20 @@ extern "C" { #endif -#include "rolls/sided_dice.h" +#include "rolls/dice_frontend.h" #include "util/vector_functions.h" + +#define MAX_SYMBOL_LENGTH 256 +#define MAX_ITERATION 20 + int roll_full_options( char* roll_request, char* log_file, int enable_verbosity, int enable_introspection, int enable_mocking, + int enable_builtins, int mocking_type, int mocking_seed ); @@ -25,6 +30,8 @@ int roll_and_write(char* s, char* f); void roll_and_write_R(int* return_code, char** s, char** f ); int mock_roll(char* s, char* f, int mock_value, int mock_const); +void load_builtins(char* root); + #ifdef __cplusplus } #endif diff --git a/src/grammar/util/array_functions.c b/src/grammar/util/array_functions.c new file mode 100644 index 000000000..18399c5eb --- /dev/null +++ b/src/grammar/util/array_functions.c @@ -0,0 +1,12 @@ + +#include "util/array_functions.h" + +int collapse(int * arr, unsigned int len){ + return sum(arr, len); +} + +int sum(int * arr, unsigned int len){ + int result = 0; + for(unsigned int i = 0; i != len; i++) result += arr[i]; + return result; +} diff --git a/src/grammar/util/array_functions.h b/src/grammar/util/array_functions.h new file mode 100644 index 000000000..f3d0ffa2c --- /dev/null +++ b/src/grammar/util/array_functions.h @@ -0,0 +1,8 @@ + +#ifndef ARRAY_FN_HEADER +#define ARRAY_FN_HEADER + +int sum(int* arr, unsigned int len); +int collapse(int* arr, unsigned int len); + +#endif diff --git a/src/grammar/rolls/mocking.c b/src/grammar/util/mocking.c similarity index 94% rename from src/grammar/rolls/mocking.c rename to src/grammar/util/mocking.c index bef52a568..5103de908 100644 --- a/src/grammar/rolls/mocking.c +++ b/src/grammar/util/mocking.c @@ -1,57 +1,57 @@ -#include "rolls/mocking.h" - -int random_fn_run_count = 0; -int global_mock_value = 0; -int secondary_mock_value = 0; -MOCK_METHOD global_mock_style = NO_MOCK; - - -void reset_mocking() { - /** - * @brief Resets various globals for test mocking - */ - random_fn_run_count = 0; - global_mock_value = 0; - global_mock_style = NO_MOCK; -} -void init_mocking(MOCK_METHOD mock_style, int starting_value) { - /** - * @brief Initializes test mocking with given settings - * @param mock_style How to apply mocking - * @param starting_value Where mocking is applied, sets the value for the - * first roll on the system - */ - random_fn_run_count = 0; - global_mock_value = starting_value; - global_mock_style = mock_style; -} - -void mocking_tick() { - /** - * @brief Every time a dice is rolled, this function is called so that the - * mocking logic can update - */ - switch (global_mock_style) { - case RETURN_INCREMENTING: { - global_mock_value = global_mock_value + 1; - break; - } - case RETURN_DECREMENTING: { - global_mock_value = global_mock_value - 1; - break; - } - case RETURN_CONSTANT_TWICE_ELSE_CONSTANT_ONE: { - if (random_fn_run_count == 1) { - secondary_mock_value = global_mock_value; - } - if (random_fn_run_count < 2) { - global_mock_value = secondary_mock_value; - } else { - global_mock_value = 1; - } - break; - } - default: - break; - } -} +#include "util/mocking.h" + +int random_fn_run_count = 0; +int global_mock_value = 0; +int secondary_mock_value = 0; +MOCK_METHOD global_mock_style = NO_MOCK; + + +void reset_mocking() { + /** + * @brief Resets various globals for test mocking + */ + random_fn_run_count = 0; + global_mock_value = 0; + global_mock_style = NO_MOCK; +} +void init_mocking(MOCK_METHOD mock_style, int starting_value) { + /** + * @brief Initializes test mocking with given settings + * @param mock_style How to apply mocking + * @param starting_value Where mocking is applied, sets the value for the + * first roll on the system + */ + random_fn_run_count = 0; + global_mock_value = starting_value; + global_mock_style = mock_style; +} + +void mocking_tick() { + /** + * @brief Every time a dice is rolled, this function is called so that the + * mocking logic can update + */ + switch (global_mock_style) { + case RETURN_INCREMENTING: { + global_mock_value = global_mock_value + 1; + break; + } + case RETURN_DECREMENTING: { + global_mock_value = global_mock_value - 1; + break; + } + case RETURN_CONSTANT_TWICE_ELSE_CONSTANT_ONE: { + if (random_fn_run_count == 1) { + secondary_mock_value = global_mock_value; + } + if (random_fn_run_count < 2) { + global_mock_value = secondary_mock_value; + } else { + global_mock_value = 1; + } + break; + } + default: + break; + } +} diff --git a/src/grammar/rolls/mocking.h b/src/grammar/util/mocking.h similarity index 87% rename from src/grammar/rolls/mocking.h rename to src/grammar/util/mocking.h index 2075216e4..f9e80c79e 100644 --- a/src/grammar/rolls/mocking.h +++ b/src/grammar/util/mocking.h @@ -1,17 +1,17 @@ - -#include "rolls/dice_enums.h" -#include "shared_header.h" - - -typedef enum { - NO_MOCK = 0, - RETURN_CONSTANT = 1, - RETURN_INCREMENTING = 2, - RETURN_DECREMENTING = 3, - RETURN_CONSTANT_TWICE_ELSE_CONSTANT_ONE = 4 -} MOCK_METHOD; - -// Mocking Util -void reset_mocking(); -void init_mocking(MOCK_METHOD mock_style, int starting_value); -void mocking_tick(); + +#include "constructs/dice_enums.h" +#include "shared_header.h" + + +typedef enum { + NO_MOCK = 0, + RETURN_CONSTANT = 1, + RETURN_INCREMENTING = 2, + RETURN_DECREMENTING = 3, + RETURN_CONSTANT_TWICE_ELSE_CONSTANT_ONE = 4 +} MOCK_METHOD; + +// Mocking Util +void reset_mocking(); +void init_mocking(MOCK_METHOD mock_style, int starting_value); +void mocking_tick(); diff --git a/src/grammar/util/safe_functions.c b/src/grammar/util/safe_functions.c index bf1ed9dcc..dfdd6f644 100644 --- a/src/grammar/util/safe_functions.c +++ b/src/grammar/util/safe_functions.c @@ -9,6 +9,80 @@ #include "shared_header.h" int gnoll_errno = 0; +extern int verbose; + + +#define ANSI_COLOR_RED "\x1b[31m" +#define ANSI_COLOR_GREEN "\x1b[32m" +#define ANSI_COLOR_RESET "\x1b[0m" + + +void print_gnoll_errors(){ + /** + * @brief A human-readable translation of the gnoll error codes + * + */ + if(verbose){ + switch(gnoll_errno){ + case SUCCESS:{ + printf("%sErrorCheck: No Errors.%s\n",ANSI_COLOR_GREEN, ANSI_COLOR_RESET); + break; + } + case BAD_ALLOC:{ + printf("%sErrorCheck: Bad Allocation.%s\n",ANSI_COLOR_RED, ANSI_COLOR_RESET); + break; + } + case BAD_FILE:{ + printf("%sErrorCheck: Bad File.%s\n",ANSI_COLOR_RED, ANSI_COLOR_RESET); + break; + } + case NOT_IMPLEMENTED:{ + printf("%sErrorCheck: Not Implemented.%s\n",ANSI_COLOR_RED, ANSI_COLOR_RESET); + break; + } + case INTERNAL_ASSERT:{ + printf("%sErrorCheck: Internal Assertion.%s\n",ANSI_COLOR_RED, ANSI_COLOR_RESET); + break; + } + case UNDEFINED_BEHAVIOUR:{ + printf("%sErrorCheck: Undefined Behaviour.%s\n",ANSI_COLOR_RED, ANSI_COLOR_RESET); + break; + } + case BAD_STRING:{ + printf("%sErrorCheck: Bad String.%s\n",ANSI_COLOR_RED, ANSI_COLOR_RESET); + break; + } + case OUT_OF_RANGE:{ + printf("%sErrorCheck: Out of Range.%s\n",ANSI_COLOR_RED, ANSI_COLOR_RESET); + break; + } + case IO_ERROR:{ + printf("%sErrorCheck: I/O Error.%s\n",ANSI_COLOR_RED, ANSI_COLOR_RESET); + break; + } + case MAX_LOOP_LIMIT_HIT:{ + printf("%sErrorCheck: Max Loop Limit Reached.%s\n",ANSI_COLOR_RED, ANSI_COLOR_RESET); + break; + } + case SYNTAX_ERROR:{ + printf("%sErrorCheck: Syntax Error.%s\n",ANSI_COLOR_RED, ANSI_COLOR_RESET); + break; + } + case DIVIDE_BY_ZERO:{ + printf("%sErrorCheck: Divide by Zero.%s\n",ANSI_COLOR_RED, ANSI_COLOR_RESET); + break; + } + case UNDEFINED_MACRO:{ + printf("%sErrorCheck: Undefined Macro.%s\n",ANSI_COLOR_RED, ANSI_COLOR_RESET); + break; + } + default:{ + printf("%sErrorCheck: Error (Undetermined. Code %i).%s\n",ANSI_COLOR_RED, gnoll_errno, ANSI_COLOR_RESET); + break; + } + } + } +} void *safe_malloc(size_t size) { /** @@ -30,6 +104,18 @@ void *safe_malloc(size_t size) { return malloc_result; } +void free_vector(vec v){ + if(v.dtype == NUMERIC){ + free(v.content); + }else{ + free_2d_array(&v.symbols, v.length); + if (v.has_source){ + // Should be always the same as length (But not sure that's true!) + free_2d_array(&v.source.symbol_pool, v.source.die_sides); + } + } +} + void free_2d_array(char ***arr, unsigned int items) { /** * @brief Free a 2d char array in a repeatable manner. @@ -38,7 +124,6 @@ void free_2d_array(char ***arr, unsigned int items) { */ if (*arr) { for (unsigned int i = 0; i != items; i++) { - // printf("[%u] Try to free: %p\n",i, (*arr)[i]); if ((*arr)[i]) { free((*arr)[i]); } @@ -57,21 +142,25 @@ void safe_copy_2d_chararray_with_allocation(char ***dst, char **src, * @param item * @param max_size */ + *dst = (char**)safe_calloc(items, sizeof(char **)); if (gnoll_errno) { return; } for (unsigned int i = 0; i != items; i++) { + (*dst)[i] = (char*)safe_calloc(sizeof(char), max_size); if (gnoll_errno) { return; } + memcpy((*dst)[i], src[i], max_size); } + } -void *safe_calloc(size_t nitems, size_t size) { +void * safe_calloc(size_t nitems, size_t size) { /** * @brief Safe version of calloc. Populates gnoll_errno on error * @param size @@ -125,7 +214,8 @@ char *safe_strdup(const char *str1) { } char *result; unsigned int l = strlen(str1) + 1; //+1 for \0 - result = (char*) safe_calloc(sizeof(char), l); + result = (char*) safe_calloc(sizeof(char), MAX_SYMBOL_LENGTH); + // result = (char*) safe_calloc(sizeof(char), l); result = strcpy(result, str1); if (result == 0) { gnoll_errno = BAD_STRING; diff --git a/src/grammar/util/safe_functions.h b/src/grammar/util/safe_functions.h index 4b1ddc328..b967e5874 100644 --- a/src/grammar/util/safe_functions.h +++ b/src/grammar/util/safe_functions.h @@ -22,6 +22,7 @@ typedef enum { UNDEFINED_MACRO = 12 } ERROR_CODES; +void print_gnoll_errors(); void *safe_malloc(size_t size); void *safe_calloc(size_t nitems, size_t size); FILE *safe_fopen(const char *filename, const char *mode); @@ -33,6 +34,8 @@ void safe_copy_2d_chararray_with_allocation(char ***dst, char **src, unsigned int max_size); void free_2d_array(char ***arr, unsigned int items); +void free_vector(vec v); + int fast_atoi(const char *str); #endif diff --git a/src/grammar/util/string_functions.c b/src/grammar/util/string_functions.c new file mode 100644 index 000000000..1a74e1e15 --- /dev/null +++ b/src/grammar/util/string_functions.c @@ -0,0 +1,41 @@ + +#include "util/string_functions.h" +#include +#include "util/safe_functions.h" + +extern int gnoll_errno; + +char * concat_strings(char ** s, unsigned int num_s){ + /** + * @brief Given an array of strings, join them together. + * @param s array of strings + * @param num_s length of above array + * @return a string containing both substrings + */ + if (num_s == 1){ + return s[0]; + } + unsigned int size_total = 0; + unsigned int spaces = 0; + for(unsigned int i = 1; i != num_s + 1; i++){ + size_total += strlen(s[i]) + 1; + } + if (num_s > 1){ + spaces = 1; + size_total -= 1; // no need for trailing space + } + + printf("Size Total %u\n", size_total); + + char * result = (char *)safe_calloc((size_total+1), sizeof(char)); + if(gnoll_errno){return NULL;} + + for(unsigned int i = 1; i != num_s + 1; i++){ + // printf() + strcat(result, s[i]); + if (spaces && i < num_s){ + strcat(result, " "); // Add spaces + } + } + return result; +} diff --git a/src/grammar/util/string_functions.h b/src/grammar/util/string_functions.h new file mode 100644 index 000000000..9d88c00e9 --- /dev/null +++ b/src/grammar/util/string_functions.h @@ -0,0 +1,4 @@ +#ifndef __STR_FNS_H__ +#define __STR_FNS_H__ +char * concat_strings(char ** s, unsigned int num_s); +#endif diff --git a/src/grammar/util/vector_functions.c b/src/grammar/util/vector_functions.c index 12f846a3a..a5682e288 100644 --- a/src/grammar/util/vector_functions.c +++ b/src/grammar/util/vector_functions.c @@ -5,10 +5,10 @@ #include #include -#include "operations/condition_checking.h" +#include "operations/conditionals.h" #include "shared_header.h" #include "util/safe_functions.h" -#include "yacc_header.h" +#include "shared_header.h" extern int gnoll_errno; @@ -23,6 +23,7 @@ void light_initialize_vector(vec *vector, DIE_TYPE dt, */ vector->dtype = dt; vector->length = number_of_items; + vector->has_source = false; if (dt == NUMERIC) { vector->content = (int*)safe_calloc(number_of_items, sizeof(int)); @@ -45,11 +46,14 @@ void initialize_vector(vec *vector, DIE_TYPE dt, unsigned int number_of_items) { vector->dtype = dt; vector->length = number_of_items; + vector->has_source = false; if (dt == NUMERIC) { vector->content = (int*)safe_calloc(number_of_items, sizeof(int)); if (gnoll_errno) return; - } else if (dt == SYMBOLIC) { + } + else if (dt == SYMBOLIC) + { vector->symbols = (char**)safe_calloc(number_of_items, sizeof(char *)); if (gnoll_errno) return; @@ -210,9 +214,18 @@ void collapse_vector(vec *vector, vec *new_vector) { } if (vector->dtype == SYMBOLIC) { - new_vector = vector; - return; - } else { + safe_copy_2d_chararray_with_allocation( + &new_vector->symbols, + vector->symbols, + vector->length, + MAX_SYMBOL_LENGTH + ); + + new_vector->length = vector->length; + new_vector->dtype = SYMBOLIC; + new_vector->has_source = false; + } + else { int c = 0; for (unsigned int i = 0; i != vector->length; i++) { c += vector->content[i]; @@ -222,16 +235,18 @@ void collapse_vector(vec *vector, vec *new_vector) { if (gnoll_errno) return; new_vector->content[0] = c; new_vector->length = 1; - new_vector->dtype = vector->dtype; + new_vector->dtype = NUMERIC; + new_vector->has_source = false; } + return; } -void keep_logic(vec *vector, vec *new_vector, unsigned int number_to_keep, +void keep_logic(vec *vector, vec *output_vector, unsigned int number_to_keep, int keep_high) { /** * @brief Collapses multiple Numeric dice to one value by summing - * @param vector source - * @param new_vector dest + * @param vector source (Freed at end) + * @param output_vector dest * @param number_to_keep how many values to keep or drop * @param keep_high Whether to keep the highest (1) or Lowest (0) values */ @@ -239,6 +254,8 @@ void keep_logic(vec *vector, vec *new_vector, unsigned int number_to_keep, return; } + unsigned int available_amount = vector->length; + if (vector->dtype == SYMBOLIC) { printf( "Symbolic Dice, Cannot determine value. Consider using filters " @@ -246,18 +263,23 @@ void keep_logic(vec *vector, vec *new_vector, unsigned int number_to_keep, gnoll_errno = UNDEFINED_BEHAVIOUR; return; } - unsigned int available_amount = vector->length; + if (available_amount > number_to_keep) { - new_vector->content = (int*)safe_calloc(sizeof(int), number_to_keep); - if (gnoll_errno) { - return; - } - new_vector->length = number_to_keep; + initialize_vector(output_vector, vector->dtype, number_to_keep); + + // output_vector->content = (int*)safe_calloc(sizeof(int), number_to_keep); + // if (gnoll_errno) { + // return; + // } + // output_vector->length = number_to_keep; int *arr = vector->content; int *new_arr; unsigned int length = vector->length; + // while (number needed) + // Get Max/Min from vector + // Store in output for (unsigned int i = 0; i != number_to_keep; i++) { int m; if (keep_high) { @@ -265,22 +287,25 @@ void keep_logic(vec *vector, vec *new_vector, unsigned int number_to_keep, } else { m = min_in_vec(arr, length); } - new_vector->content[i] = m; + output_vector->content[i] = m; new_arr = (int*)safe_calloc(sizeof(int), length - 1); if (gnoll_errno) { return; } + // Take 'm' out of the array (put in new_array) pop(arr, length, m, new_arr); free(arr); arr = new_arr; length -= 1; } - new_vector->dtype = vector->dtype; + free(arr); + // output_vector->content = arr; + output_vector->dtype = vector->dtype; } else { // e.g. 2d20k4 / 2d20kh2 printf("Warning: KeepHighest: Keeping <= produced amount"); - new_vector = vector; + output_vector = vector; } } diff --git a/src/grammar/util/vector_functions.h b/src/grammar/util/vector_functions.h index 1f2ac5aac..187d19f61 100644 --- a/src/grammar/util/vector_functions.h +++ b/src/grammar/util/vector_functions.h @@ -1,8 +1,8 @@ #ifndef VECFN_HEADER #define VECFN_HEADER -#include "rolls/dice_enums.h" -#include "rolls/vec.h" +#include "constructs/dice_enums.h" +#include "constructs/vec.h" #include "shared_header.h" void initialize_vector(vec* vector, DIE_TYPE dt, unsigned int number_of_items); diff --git a/src/grammar/yacc_header.h b/src/grammar/yacc_header.h deleted file mode 100644 index 5d0d9e0c9..000000000 --- a/src/grammar/yacc_header.h +++ /dev/null @@ -1,16 +0,0 @@ - -#ifndef __YACC_HEADER__ -#define __YACC_HEADER__ - -#define MAX_SYMBOL_LENGTH 256 -#define MAX_ITERATION 20 - -int initialize(); -// int resolve_dice(dice die); - -int sum(int* arr, unsigned int len); -int collapse(int* arr, unsigned int len); -int roll_numeric_die(int small, int big); -int roll_symbolic_die(unsigned int length_of_symbolic_array); - -#endif diff --git a/src/python/code/gnoll/parser.py b/src/python/code/gnoll/parser.py index 92a9c4836..9314c71d0 100644 --- a/src/python/code/gnoll/parser.py +++ b/src/python/code/gnoll/parser.py @@ -3,8 +3,6 @@ import tempfile from ctypes import cdll -from wurlitzer import pipes - BUILD_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "c_build")) C_SHARED_LIB = os.path.join(BUILD_DIR, "dice.so") @@ -45,7 +43,7 @@ def raise_gnoll_error(value): raise err -def roll(s, verbose=False, mock=None, mock_const=3, breakdown=False): +def roll(s, verbose=False, mock=None, mock_const=3, breakdown=False, builtins=False): """ Parse some dice notation with GNOLL. @param s the string to parse @@ -55,9 +53,9 @@ def roll(s, verbose=False, mock=None, mock_const=3, breakdown=False): @param breakdown get the details of each dice rolled, not just the final result @return return code, final result, dice breakdown (None if disabled) """ - temp = tempfile.NamedTemporaryFile(prefix="gnoll_roll_", - suffix=".die", - delete=False) + temp = tempfile.NamedTemporaryFile( + prefix="gnoll_roll_", suffix=".die", delete=False + ) def make_native_type(v): """ @@ -92,25 +90,18 @@ def extract_from_dice_file(lines, seperator): print("Rolling: ", s) print("Output in:", out_file) - with pipes() as (out, err): - s = s.encode("ascii") - - return_code = libc.roll_full_options( - s, - out_file, - False, # enable_verbose - breakdown, # enable_introspect - mock is not None, # enable_mock - mock, - mock_const, - ) - - if verbose: - print("---stdout---") - print(out.read()) - print("---stderr---") - print(err.read()) - + s = s.encode("ascii") + + return_code = libc.roll_full_options( + s, + out_file, + True, # enable_verbose + breakdown, # enable_introspect + mock is not None, # enable_mock + builtins, # enable_builtins + mock, + mock_const, + ) if return_code != 0: raise_gnoll_error(return_code) @@ -127,9 +118,11 @@ def extract_from_dice_file(lines, seperator): arg = "".join(sys.argv[1:]) arg = arg if arg != "" else "1d20" code, r, detailed_r = roll(arg, verbose=False) - print(f""" + print( + f""" [[GNOLL Results]] Dice Roll: {arg} Result: {r} Exit Code: {code}, -Dice Breakdown: {detailed_r}""") +Dice Breakdown: {detailed_r}""" + ) diff --git a/tests/python/test_macros.py b/tests/python/test_macros.py index 522f35444..9c481998f 100644 --- a/tests/python/test_macros.py +++ b/tests/python/test_macros.py @@ -19,15 +19,13 @@ def test_macro_storage(r, out, mock): assert result == out -@pytest.mark.parametrize("r,out,mock", - [("#MY_DIE=d{A};@MY_DIE", "A", Mock.NO_MOCK)]) +@pytest.mark.parametrize("r,out,mock", [("#MY_DIE=d{A};@MY_DIE", "A", Mock.NO_MOCK)]) def test_macro_usage(r, out, mock): result, _ = roll(r, mock_mode=mock) assert result == out -@pytest.mark.skip("Currently no support for rerolling operations like Addition" - ) +@pytest.mark.skip("Currently no support for rerolling operations like Addition") def test_d66(): r = "#DSIXTYSIX=(d6*10)+d6;@DSIXTYSIX" result, _ = roll(r, mock_mode=Mock.RETURN_CONSTANT, mock_const=3) @@ -44,7 +42,10 @@ def test_multiple_external_calls_macros(): result = [] r = "#TEST=d{A,B,C,D};@TEST;" for _ in range(20): - result.append(roll(r)) + print("~~~~ ROLL~~~~") + x = roll(r) + result.append(x) + print(x) assert not all(r == result[0] for r in result) @@ -55,6 +56,12 @@ def test_undefined_macro(): error_handled_by_gnoll(e) +# @pytest.mark.skip("Temporary Failure") +def test_predefined_macro(): + r = roll("@ORACLE", builtins=True)[0] + assert r in ["YES", "YES_AND", "YES_BUT", "NO", "NO_AND", "NO_BUT"] + + def test_builtins(): # Check that builtins are valid calls here = os.path.dirname(os.path.abspath(__file__)) diff --git a/tests/python/util.py b/tests/python/util.py index 5b481e31d..d530892be 100644 --- a/tests/python/util.py +++ b/tests/python/util.py @@ -6,9 +6,11 @@ import numpy as np GRAMMAR_DIR = os.path.abspath( - os.path.join(os.path.dirname(__file__), "../../src/grammar")) + os.path.join(os.path.dirname(__file__), "../../src/grammar") +) SRC_DIR = os.path.abspath( - os.path.join(os.path.dirname(__file__), "../../src/python/code/gnoll/")) + os.path.join(os.path.dirname(__file__), "../../src/python/code/gnoll/") +) MK_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../")) first_run = True @@ -52,7 +54,9 @@ def make_all(): raise ValueError -def roll(s, mock_mode=Mock.NO_MOCK, mock_const=3, verbose=False, squeeze=True): +def roll( + s, mock_mode=Mock.NO_MOCK, mock_const=3, verbose=False, squeeze=True, builtins=False +): global first_run if first_run: @@ -63,11 +67,14 @@ def roll(s, mock_mode=Mock.NO_MOCK, mock_const=3, verbose=False, squeeze=True): # Get module now - post make dice_tower_roll = get_roll() - dt_return = dice_tower_roll(s, - mock=mock_mode.value, - mock_const=mock_const, - verbose=verbose, - breakdown=True) + dt_return = dice_tower_roll( + s, + mock=mock_mode.value, + mock_const=mock_const, + verbose=verbose, + breakdown=True, + builtins=builtins, + ) exit_code = dt_return[0] result = dt_return[1] dice_breakdown = dt_return[2] if len(dt_return) > 2 else []