%{ #include #include #include #include "../config.h" #include "zmachine.h" #include "rc.h" #include "rcp.h" #include "hash.h" #define YYERROR_VERBOSE 1 extern int _rc_line; extern hash rc_hash; extern void rc_error(char*); extern int rc_lex(void); int rc_merging = 0; #define EMPTY_GAME(x) x.fg_col = -1; x.bg_col = -1; x.interpreter = -1; x.revision = -1; x.name = NULL; x.fonts = NULL; x.n_fonts = -1; x.colours = NULL; x.n_colours = -1; x.gamedir = x.savedir = x.sounds = x.graphics = NULL; x.xsize = x.ysize = -1; x.antialias = -1; static inline rc_game merge_games(const rc_game* a, const rc_game* b) { rc_game r; if (a->fg_col == -1) r.fg_col = b->fg_col; else r.fg_col = a->fg_col; if (a->bg_col == -1) r.bg_col = b->bg_col; else r.bg_col = a->bg_col; if (a->interpreter == -1) r.interpreter = b->interpreter; else r.interpreter = a->interpreter; if (a->antialias == -1) r.antialias = b->antialias; else r.antialias = a->antialias; if (a->revision == -1) r.revision = b->revision; else r.revision = a->revision; if (a->name == NULL) r.name = b->name; else r.name = a->name; if (a->fonts == NULL) { r.fonts = b->fonts; r.n_fonts = b->n_fonts; } else if (b->fonts == NULL) { r.fonts = a->fonts; r.n_fonts = a->n_fonts; } else { int x; r.n_fonts = a->n_fonts + b->n_fonts; r.fonts = malloc(r.n_fonts*sizeof(rc_font)); for (x=0; xn_fonts; x++) r.fonts[x] = a->fonts[x]; for (x=0; xn_fonts; x++) r.fonts[x+a->n_fonts] = b->fonts[x]; free(a->fonts); free(b->fonts); } if (a->colours == NULL) { r.colours = b->colours; r.n_colours = b->n_colours; } else if (b->colours == NULL) { r.colours = a->colours; r.n_colours = a->n_colours; } else rc_error("Can only have one set of colours per block"); if (a->gamedir == NULL) r.gamedir = b->gamedir; else r.gamedir = a->gamedir; if (a->savedir == NULL) r.savedir = b->savedir; else r.savedir = a->savedir; if (a->sounds == NULL) r.sounds = b->sounds; else r.sounds = a->sounds; if (a->graphics == NULL) r.graphics = b->graphics; else r.graphics = a->graphics; if (a->xsize == -1) r.xsize = b->xsize; else r.xsize = a->xsize; if (a->ysize == -1) r.ysize = b->ysize; else r.ysize = a->ysize; return r; } %} %union { char* str; int num; char chr; rc_font font; rc_game game; rc_colour col; stringlist* slist; } %token DEFAULT %token INTERPRETER %token REVISION %token FONT %token COLOURS %token GAME %token ROMAN %token BOLD %token ITALIC %token FIXED %token SYMBOLIC %token GAMEDIR %token SAVEDIR %token SOUNDS %token GRAPHICS %token SIZE %token ANTIALIAS %token YES %token NO %token GAMEID %token NUMBER %token STRING %token CHARACTER %type ColourDefn %type ColourList %type RevisionList %type GoodRevisionList %type FontQual %type FontDefn %type FontType %type RCOption %type RCOptionList %type RCBlock %type YesOrNo %{ static int check_collision(char* ourid, char* name) { rc_game* game; game = hash_get(rc_hash, ourid, strlen(ourid)); if (game != NULL && strcmp(name, game->name) != 0) { if (!rc_merging) zmachine_info("Namespace collision: identifier '%s' (for game '%s') already used for game '%s'", ourid, name, game->name); return 0; } return 1; } %} %% RCFile: RCDefn | RCFile RCDefn ; RCDefn: DEFAULT STRING RCBlock { rc_game* game; if (!rc_merging) { game = malloc(sizeof(rc_game)); *game = $3; game->name = $2; hash_store(rc_hash, (unsigned char*)"default", 7, game); } } | DEFAULT RCBlock { rc_game* game; if (!rc_merging) { game = malloc(sizeof(rc_game)); *game = $2; game->name = "%s"; hash_store(rc_hash, (unsigned char*)"default", 7, game); } } | GAME STRING RevisionList { if ($3 != NULL) { rc_game* game; stringlist* next; game = malloc(sizeof(rc_game)); EMPTY_GAME((*game)); game->name = $2; next = $3; while (next != NULL) { if (check_collision(next->string, game->name)) { hash_store(rc_hash, (unsigned char*)next->string, strlen(next->string), game); } next = next->next; } } else { zmachine_info(".zoomrc has erroneous entry for game '%s' (line %i)", $2, _rc_line); } } | GAME STRING RevisionList RCBlock { if ($3 != NULL) { rc_game* game; stringlist* next; game = malloc(sizeof(rc_game)); *game = $4; game->name = $2; next = $3; while (next != NULL) { if (check_collision(next->string, game->name)) { hash_store(rc_hash, (unsigned char*)next->string, strlen(next->string), game); } next = next->next; } } else { zmachine_info(".zoomrc has erroneous entry for game '%s' (line %i)", $2, _rc_line); } } ; RCBlock: '{' RCOptionList '}' { $$ = $2; } | '{' '}' { EMPTY_GAME($$); } | '{' ErrorList { yyerrok; zmachine_info(".zoomrc options block ending at line %i makes no sense", _rc_line); EMPTY_GAME($$); } | '{' RCOptionList ErrorList { yyerrok; $$ = $2; zmachine_info(".zoomrc options block at line %i has syntax errors", _rc_line); } ; RCOptionList: RCOption | RCOptionList RCOption { $$ = merge_games(&$1, &$2); } ; YesOrNo: YES { $$ = 1; } | NO { $$ = 0; } ; RCOption: INTERPRETER NUMBER { EMPTY_GAME($$); $$.interpreter = $2; } | ANTIALIAS YesOrNo { EMPTY_GAME($$); $$.antialias = $2; } | REVISION CHARACTER { EMPTY_GAME($$); $$.revision = $2; } | FONT NUMBER STRING FontType { EMPTY_GAME($$); $$.fonts = malloc(sizeof(rc_font)); $$.n_fonts = 1; $$.fonts[0] = $4; $$.fonts[0].name = $3; $$.fonts[0].num = $2; } | COLOURS ColourList { $$ = $2; } | GAMEDIR STRING { EMPTY_GAME($$); $$.gamedir = $2; } | SAVEDIR STRING { EMPTY_GAME($$); $$.savedir = $2; } | SOUNDS STRING { EMPTY_GAME($$); $$.sounds = $2; } | GRAPHICS STRING { EMPTY_GAME($$); $$.graphics = $2; } | SIZE NUMBER ',' NUMBER { EMPTY_GAME($$); $$.xsize = $2; $$.ysize = $4; } ; FontType: FontDefn { $$.name = NULL; $$.attributes[0] = $1; $$.n_attr = 1; $$.num = 0; } | FontType ',' FontDefn { $$ = $1; $$.n_attr++; $$.attributes[$$.n_attr-1] = $3; } ; FontDefn: FontQual { $$ = $1; } | FontDefn '-' FontQual { $$ = $1|$3; } ; FontQual: ROMAN { $$ = 0; } | BOLD { $$ = 1; } | ITALIC { $$ = 2; } | FIXED { $$ = 4; } | SYMBOLIC { $$ = 8; } ; ColourList: ColourDefn { EMPTY_GAME($$); $$.colours = malloc(sizeof(rc_colour)); $$.colours[0] = $1; $$.n_colours = 1; } | ColourList ',' ColourDefn { $$ = $1; $$.n_colours++; $$.colours = realloc($$.colours, sizeof(rc_colour)*$$.n_colours); $$.colours[$$.n_colours-1]=$3; } ; ColourDefn: '(' NUMBER ',' NUMBER ',' NUMBER ')' { $$.r = $2&0xff; $$.g = $4&0xff; $$.b = $6&0xff; } ; RevisionList: GoodRevisionList | BadRevisionList { $$ = NULL; } ; BadRevisionList: ErrorList { yyerrok; } ; GoodRevisionList: GAMEID { $$ = malloc(sizeof(stringlist)); $$->next = NULL; $$->string = $1; } | RevisionList ',' GAMEID { if ($1 == NULL) { $$ = NULL; } else { $$ = malloc(sizeof(stringlist)); $$->next = $1; $$->string = $3; } } ; ErrorList: error '}' { yyerrok; } ; %%