From 0dc97f87cbbe47ef84501678f302404d042428b1 Mon Sep 17 00:00:00 2001 From: ken Date: Thu, 5 Jan 2017 09:42:53 -0800 Subject: [PATCH] wip --- src/apc.c | 6 +- src/apc.h | 11 +- src/ir.c | 1093 +++++++++---------------------------------------- src/ir.h | 87 +++- src/parser.y | 261 ++++++------ src/scanner.c | 8 +- 6 files changed, 418 insertions(+), 1048 deletions(-) diff --git a/src/apc.c b/src/apc.c index cea3847..3b5774f 100644 --- a/src/apc.c +++ b/src/apc.c @@ -17,11 +17,13 @@ #include //strndupa /* Posix */ #include //exit -#include //getopt +#include //getopt, sysconf /* Internal */ #include "parser.tab.h" //bison +#define DEFAULT_PAGESIZE 4096 const char* cargs['Z'] = {0}; +const long sys_pagesize; int main(int, char*[]); @@ -76,6 +78,8 @@ int main printf(USAGE_LONG); exit(EXIT_SUCCESS); } + if ((sys_pagesize = sysconf(_SC_PAGESIZE)) == 0) + sys_pagesize = DEFAULT_PAGESIZE; if (lexer_init() || ir_init()) { perror("init"); exit(EXIT_FAILURE); diff --git a/src/apc.h b/src/apc.h index 6a8df1e..efed4d4 100644 --- a/src/apc.h +++ b/src/apc.h @@ -1,6 +1,5 @@ -#include -#include -#include +#ifndef _APC_H_ +#define _APC_H_ //ir.h #define BUF_SIZE 256 @@ -26,8 +25,4 @@ #define FNAME_MAX 1024 #define FPATH_MAX 8192 - -struct name -{ - uint8_t name[MAX_NAME_LEN]; -}; +#endif //_APC_H_ diff --git a/src/ir.c b/src/ir.c index 4325813..49480ab 100644 --- a/src/ir.c +++ b/src/ir.c @@ -4,915 +4,196 @@ \author Jordan Lavatai \date Aug 2016 ----------------------------------------------------------------------------*/ -#include -#include -#include //uint8_t as a char -#include //u32_cpy +/* Standard */ +#include //exit, malloc +#include //print +#include //va_args #include //uint64_t -#include //memset -#include //u8_* functions +#include //memset, str* +/* Unicode */ +#include //u8_* functions +#include //uint8_t as a char +#include //u32_cpy +/* Local */ #include "apc.h" - - -extern -int -name_u8_cpy(struct name*, struct name*); - -extern -int -name_u8_cmp(struct name*, struct name*); - -extern -int -name_u8_set(struct name*, ucs4_t); - -int -ir_init(void); -struct cdat* -alloc_cdat(void); -struct odat* -alloc_odat(void); -void -alloc_vdat(void); -struct link* -alloc_link(void); -struct ref* -alloc_ref(void); -struct set* -alloc_set(void); -struct cdat* -curr_cdat(void); -struct odat* -curr_odat(void); -struct vdat* -curr_vdat(void); -struct map* -curr_map(void); -struct set* -curr_cdat_set(void); -struct set* -curr_set(void); -struct ref* -curr_ref(void); -struct model* -curr_model(void); - -/* ir.c */ -void -inc_posts(void); -void -push_cdat(struct name*); -void -pop_cdat(void); -void -insert_refid(int); -void -insert_link_name(struct name*); -void -insert_link_namelist(struct name*); -void -insert_ss_name(struct name*); -void -insert_ss_namelist(struct name*); -void -insert_mlink(struct name*, int); -void -insert_vlink(struct name*, int); -void -insert_ref(struct odat*, int); -void -alloc_vdat(void); -void -insert_vdat(void); -void -insert_map(struct name*, int, int, int, int, uint8_t*); -void -insert_framesheet(struct name*, int, int, int, int, uint8_t*); - - - -//type safety handled by macro expansion (do not call these directly from code, make dependent macros for access to these) -#define CHUNKS_LEN(STACK) ((STACK).csp - (STACK).chunks) -#define CURRENT_CHUNK(STACK) ((STACK).chunks[CHUNKS_LEN(STACK) - 1]) -#define CHUNKS_FULL(STACK) ( (STACK).csp >= \ - (STACK).chunks + MAX_CHUNKS * (STACK).chunk_size) -#define CURRENT_DSP(STACK,TYPE) ((TYPE*) ((STACK).dsp[CHUNKS_LEN(STACK) - 1])) -#define DATA_FULL(STACK,TYPE) ((void*) CURRENT_DSP(STACK,TYPE) >= \ - (CURRENT_CHUNK(STACK) + (STACK).chunk_size)) -#define CSP_PUSH(STACK) (*(++(STACK).csp) = malloc((STACK).chunk_size)) -#define CURRENT_DATP(STACK,TYPE) (((TYPE**)(STACK).dsp)[CHUNKS_LEN(STACK) - 1]) -#define PREVIOUS_DATP(STACK,TYPE) (((TYPE**)(STACK).dsp)[CHUNKS_LEN(STACK) - 2]) -#define ALLOC_DAT(STACK,TYPE) (++CURRENT_DATP(STACK,TYPE)) -#define INIT_STACK(STACK,TYPE) \ - { int i; \ - (STACK).chunk_size = PAGES_PER_CHUNK * pagesize; \ - (STACK).max_dats = (STACK).chunk_size / sizeof (TYPE); \ - CSP_PUSH(STACK); \ - for( i = 0; i < MAX_CHUNKS; i++){ \ - (STACK).dsp[i] += pagesize; \ - } \ - } -//Stack-specific macros (called directly from code (safety enforcement) -#define INIT_ODAT() (INIT_STACK(ocs, struct odat)) -#define CURRENT_ODAT() (CURRENT_DATP(ocs,struct odat)) -#define ODAT_FULL() (DATA_FULL(ocs,struct odat)) -#define ODAT_ALLOC() (ALLOC_DAT(ocs,struct odat)) -#define OCS_FULL() (CHUNKS_FULL(ocs)) -#define INIT_VDAT() (INIT_STACK(vcs, struct vdat)) -#define CURRENT_VDAT() (CURRENT_DATP(vcs,struct vdat)) -#define VDAT_FULL() (DATA_FULL(vcs,struct vdat)) -#define VDAT_ALLOC() (ALLOC_DAT(vcs,struct vdat)) -#define VCS_FULL() (CHUNKS_FULL(vcs)) -#define INIT_CDAT() (INIT_STACK(ccs, struct cdat)) -#define CURRENT_CDAT() (CURRENT_DATP(ccs,struct cdat)) -#define CDAT_FULL() (DATA_FULL(ccs, struct cdat)) -#define CDAT_ALLOC() (ALLOC_DAT(ccs, struct cdat)) -#define CCS_FULL() (CHUNKS_FULL(ccs)) -#define INIT_SET() (INIT_STACK(scs, struct set)) -#define CURRENT_SET() (CURRENT_DATP(scs, struct set)) -#define SET_FULL() (DATA_FULL(scs, struct set)) -#define SET_ALLOC() (ALLOC_DAT(scs, struct set)) -#define SCS_FULL() (CHUNKS_FULL(scs)) -#define INIT_LINK() (INIT_STACK(lcs, struct link)) -#define CURRENT_LINK() (CURRENT_DATP(lcs,struct link)) -#define LDAT_FULL() (DATA_FULL(lcs, struct link)) -#define LDAT_ALLOC() (ALLOC_DAT(lcs, struct link)) -#define LCS_FULL() (CHUNKS_FULL(lcs)) -#define INIT_POST() (INIT_STACK(rcs, struct ref)) -#define CURRENT_POST() (CURRENT_DATP(pcs,struct ref)) -#define POST_FULL() (DATA_FULL(pcs,struct ref)) -#define POST_ALLOC() (ALLOC_DAT(pcs,struct ref)) -#define PCS_FULL() (CHUNKS_FULL(pcs)) -#define INIT_REF() (INIT_STACK(rcs, struct ref)) -#define CURRENT_REF() (CURRENT_DATP(rcs,struct ref)) -#define PREVIOUS_REF() (PREVIOUS_DATP(rcs, struct ref)) -#define REF_FULL() (DATA_FULL(rcs,struct ref)) -#define REF_ALLOC() (ALLOC_DAT(rcs,struct ref)) -#define RCS_FULL() (CHUNKS_FULL(rcs)) -//Metadata -#define CURRENT_MODEL() (CURRENT_VDAT()->model_list[CURRENT_VDAT()->num_models]) - - - - -/* Cdats: A cdat is a class data structure. Cdats serve as the central */ -/* data types of the IR. Cdats contain pointers to their subclasses so that the relationship between */ -/* classes can be determined, but the subclasses are not represented inside */ -/* of the cdat itself but rather in subsequent cdats in cdat_buf. We */ -/* can determine the number of subclasses (the last index into cdat_buf */ -/* that represents a subclass of some arbitrary cdat) each cdat has by */ -/* incrementing num_classes during parse time. */ -/* TODO: Should classes point to their parent class? */ -/* TODO: Talk more about cdat set structure */ - -struct cdat { - struct name name; - int idx; - int num_classes; - int num_sets; - struct cdat* class_list[MAX_CLASSES]; - struct set* set_list[MAX_SETS]; -}; - - -struct set { - int cdat_idx; - int num_sets; - struct set* set_list[MAX_SETS]; -}; - -struct ref { - struct ref* nextref; - struct ref* lastref; - struct odat* odatp; - int refid; //0xFFFFFF->digit -}; - -struct olink { - int src_refid; -}; - -struct vlink { - int src_refid; - struct name src_animname; - struct name src_namelist[MAX_DEPTH]; -}; - -struct mlink { - int src_refid; - struct name src_mapname; - struct name src_namelist[MAX_DEPTH]; - +#include "ir.h" +/* Public */ +int ir_init(void); +int ir_linker(void); +int ir_condenser(void); +#if 0 +ir_class ir_class_findchild(ir_class, uint8_t*); +ir_set ir_class_rootset(ir_class); +ir_class ir_class_nextsib(ir_class); +ir_class ir_class_nextchild(ir_class); +uint8_t* ir_class_name(ir_class); +ir_set ir_class_findset(ir_class,uint8_t*); +ir_set ir_set_findchild(ir_set, uint8_t*); +ir_set ir_set_nextsib(ir_set); +ir_set ir_set_nextchild(ir_set); +ir_set ir_set_findref(long long); +uint8_t* ir_set_name(ir_set); +#endif +/* Private */ +static inline +uint8_t bytes_identical(uint8_t*,uint8_t*); + +/* Enumerated types */ +enum dtype { FSDAT, MSDAT, ADAT, LDAT }; +enum ltype { OLINK, MLINK, VLINK, ALINK }; +/* Set data mem */ +struct sdat_header_t +{ enum dtype type; + uint8_t* src_file_name; + uint8_t* data_name; }; - -union link_t { - struct vlink vlink; - struct mlink mlink; - struct olink olink; +struct frameinfo_t +{ int facing, w, h; }; - - -/* Links are a mechanism for designers to indicate in the grammar that a odat, vdat, or map - is defined elsewhere and that the link should be replaced with the specified odat/vdat/map */ -struct link { - int type; //1 = olink, 2 = vlink, 3 = mlink - union link_t link_t; - int dest_refid; //if it exists - struct odat* dest_odatp; - +struct framedata_t +{ struct sdat_header_t header; + struct frameinfo_t frameinfo; +} **framedatas; +struct framebox_t +{ struct framedata_t framesheets[FACE_MAX]; + struct framedata_t mapsheets[FACE_MAX]; + uint8_t *data_name; +} **frameboxes; +struct simplex_t +{ struct sdat_header_t header; +} **simplexes; +struct link_t +{ struct sdat_header_t header; + struct set_t *src, *trg; + enum ltype type; +} **links; +union sdat_t +{ struct sdat_header_t header; + struct framedata_t framesheet; + struct framedata_t mapsheet; + struct simplex_t audio; + struct link_t link; }; - -struct map { - struct name name; - int height; - int width; - uint8_t filepath[FPATH_MAX]; -}; - -/* Odats: Odats consist of the object data necessary for - each object. Odats are sometimes referred to as archetypes - at compile-time, in order to distinguish the difference from - a runtime object and a compile-time object. - TODO: Need more info about objects at runtime, to described - the reasoning behind odat structure at compile-time*/ -struct odat { - struct name name; - int refid; - int ismap; - int vdat_idx; - struct link* linkp; - struct vdat* vdatp; - struct odat* parent_odatp; /* null if parent is a cdat */ - struct ref* refp; /* pointer to it's ref on ref_list */ - struct map map; /* only valid if odat ismap */ - -}; - -/* A framesheet is a grouping of animation frames in a single direction (N,W,S,E, etc.). Framesheets - also hold the framesheet dimensions and the filepath to the png of the framesheet so the file can be opened - and the png data can be extracted. */ -struct framesheet { - int width; - int height; - uint8_t filepath[FPATH_MAX]; - int num_frames; - -}; - -/* A model is a collection of framesheets for every - direction (N,W,S,E,NW,NE,SW,SE). Currently, users can only define - framesheets in the APC grammar, which are inserted into the current model*/ -struct model { - struct name name; - struct framesheet spritesheet[8]; //one for each -}; - -/* Vdat: Vdats are the video data of each object. Vdats have a list of models for every - animation that the vdats odat can do for that vdat. */ -struct vdat { - struct odat* creator; //pointer to odat that made this vdat - int num_models; - struct model model_list[MAX_MODELS]; -}; - -/* An entry on the set_stack that describes the namelist and relevant information for - the current set that is being processed in the parser. For each set name, - there is a corresponding set/odat that is created when set names are encountered. */ - -struct set_frame -{ struct name namelist[MAX_DEPTH]; - int num_names; - struct set* setp; - struct odat* odatp; -} ; - -/* Stores the last defined set at every depth */ -struct set_stack -{ struct set_frame set_frames[MAX_DEPTH]; - int curr_depth; //used to get most recently created set/odat + to check for undefined parents of namelists -}; - - -//"type free" chunk stacking -struct chunk_stack -{ void* chunks[MAX_CHUNKS]; - void* *csp; //chunk stack pointer - void* dsp[MAX_CHUNKS]; //dat stack pointer (per chunk) - int chunk_size; //size of a chunk (including its forfeited page) - int max_dats; //number of dats per chunk for this stack -} ocs, vcs, ccs, rcs, lcs, pcs, scs; //odat, vdat, cdat, ref, link, post stacks - -/* The cdat_stack is a stack pointers to cdat pointers, the top of which is - the cdat that is currently being parsed. Whenever a new cdat is recognized - by the grammar (CLOPEN), a cdat is pushed onto the cdat_stack, and we refer - to this cdat through the macro CURR_CDAT. By keeping a cdat_stack, we have - access to the current cdat so that the elements and sets can populate themselves - in the cdat accordingly. */ - -struct cdat* cdat_stack[MAX_CLASSES]; -struct cdat** cdat_stackp; - - - -struct set_stack ss; -struct name set_namelist[MAX_DEPTH]; -int set_numnames = 0; - -struct name link_namelist[MAX_DEPTH]; -int link_numnames = 0; - -int num_cdats = 0; -int num_odats = 0; -int num_vdats = 0; -int num_sets = 0; -int num_refs = 0; -int ss_refid = 0x0FFFFFFF; /* system space for refids */ -int num_posts = 0; -int num_links = 0; -int num_models = 0; -long pagesize = 0; - - -/* The initalization function of the IR. */ -int -ir_init() -{ struct name name; - - - uint8_t root[4] = "root"; - - u8_stpncpy(name.name, root, 4); - - pagesize = sysconf(_SC_PAGESIZE); - - INIT_CDAT(); - *cdat_stackp = CURRENT_CDAT(); - name_u8_cpy(&(*cdat_stackp)->name, &name); - - INIT_ODAT(); - INIT_VDAT(); - VDAT_ALLOC(); //NULL vdat - VDAT_ALLOC(); //First vdat req. because alloc_vdat happens after vdat is reduced - INIT_SET(); - INIT_LINK(); - INIT_REF(); - INIT_POST(); - - - return 0; - -} - -void -ir_quit() -{ - int i; - - for(i = 0; i < CHUNKS_LEN(ccs) ; i++) - { - free(ccs.chunks[i]); - } - for(i = 0; i < CHUNKS_LEN(ocs); i++) - { - free(ocs.chunks[i]); - } - for(i = 0; i < CHUNKS_LEN(vcs) ; i++) - { - free(vcs.chunks[i]); - } - for(i = 0; i < CHUNKS_LEN(rcs); i++) - { - free(rcs.chunks[i]); - } - for(i = 0; i < CHUNKS_LEN(lcs); i++) - { - free(lcs.chunks[i]); - } - for(i = 0; i < CHUNKS_LEN(pcs); i++) - { - free(pcs.chunks[i]); - } - -} - -struct cdat* -alloc_cdat() -{ - num_cdats++; - if(CDAT_FULL()) - { if(CCS_FULL()) - { fprintf(stderr, "You have allocated to many (%d) cdats ", num_cdats); - exit(EXIT_FAILURE); - } - else - CSP_PUSH(ccs); - } - else - CDAT_ALLOC(); - - return CURRENT_CDAT(); -} - -//these should probably be inline -struct odat* -alloc_odat -() -{ - num_odats++; - if(ODAT_FULL()) - { if(!OCS_FULL()) - { fprintf(stderr, "You have allocated to many (%d) odats ", num_odats); - exit(EXIT_FAILURE); - } - else - CSP_PUSH(ocs); - } - else - ODAT_ALLOC(); - - return CURRENT_ODAT(); -} - -void -alloc_vdat -() -{ num_vdats++; - if(VDAT_FULL()) - { if(!VCS_FULL()) - { fprintf(stderr, "You have allocated to many (%d) vdats ", num_vdats); - exit(EXIT_FAILURE); - } - else - CSP_PUSH(vcs); - } - else - VDAT_ALLOC(); - - -} - -struct set* -alloc_set -() -{ num_sets++; - if(SET_FULL()) - { if(!SCS_FULL()) - { fprintf(stderr, "You have allocated to many (%d) sets ", num_sets); - exit(EXIT_FAILURE); - } - else - CSP_PUSH(scs); - } - else - SET_ALLOC(); - - return CURRENT_SET(); -} - - -struct link* -alloc_link -() -{ num_links++; - if(LDAT_FULL()) - { if(!LCS_FULL()) - { fprintf(stderr, "You have allocated to many (%d) links ", num_links); - exit(EXIT_FAILURE); - } - else - CSP_PUSH(lcs); - } - else - LDAT_ALLOC(); - - return CURRENT_LINK(); - -} - -struct ref* -alloc_ref -() -{ num_refs++; - if(REF_FULL()) - { if(!RCS_FULL()) - { fprintf(stderr, "You have allocated to many (%d) refs ", num_refs); - exit(EXIT_FAILURE); - } - else - CSP_PUSH(rcs); - } - else - REF_ALLOC(); - - - if(num_refs % 16 == 0) - { CURRENT_POST() = CURRENT_REF(); - inc_posts(); - } - - return CURRENT_REF(); -} - -void -inc_posts() -{ num_posts++; - if(POST_FULL()) - { if(!PCS_FULL()) - { fprintf(stderr, "You have allocated to many (%d) refs ", num_posts); - exit(EXIT_FAILURE); - } - else - CSP_PUSH(pcs); - } - else - POST_ALLOC(); - -} - -struct cdat* -curr_cdat -() -{ - return (*cdat_stackp); -} - -struct odat* -curr_odat -() -{ - return CURRENT_ODAT(); -} - -struct vdat* -curr_vdat -() -{ - return CURRENT_VDAT(); -} -struct set* -curr_cdat_set -() -{ - return CURRENT_SET(); -} - -struct ref* -curr_ref -() -{ - return CURRENT_REF(); -} -struct ref* -prev_ref -() -{ - return PREVIOUS_REF(); -} -struct model* -curr_model -() -{ - return &CURRENT_MODEL(); -} - -/* IR.C*/ -void -push_cdat -( struct name* name ) -{ - struct cdat* curr_cdatp; - - curr_cdatp = alloc_cdat(); - - name_u8_cpy(&curr_cdatp->name, name); - curr_cdatp->idx = num_cdats; - - /* Set the cdat as a subclass of the previous cdat */ - (*cdat_stackp)->class_list[(*cdat_stackp)->num_classes++] = curr_cdatp; - /* Push the cdat onto the cdat_stack */ - *++cdat_stackp = curr_cdatp; - -} - -void -pop_cdat -() -{ - cdat_stackp--; -} - - - -void -insert_set_name -( struct name* name ) -{ - //Push name onto current namelist, set the set_namelist. - name_u8_cpy(&set_namelist[set_numnames++], name); - -} - - -/* Called at the last name of a sets namelist. Inserts the set namelist - onto the set_stack at the appropriate depth i.e. the number of names in - the namelist. If each name in the namelist at every depth matches, nothing happens. For every - name on the namelist that doesnt match what is currently on the set_stack, - a new set/odat is created at the depth that it describes. E.g. a set name - of A_B_C is a depth of 3 and is represented in the set_stack as A, A_B and A_B_C. - If a new set namelist is defined, X_Y, the new set_stack will become X, X_Y. */ - -void -insert_set_namelist -( struct name* name ) -{ int depth, nameidx, i; - - insert_set_name(name); - - - for( depth = 0; depth < set_numnames ; depth++ ) - { for (nameidx = 0; nameidx <= depth; nameidx++) - { if( name_u8_cmp(&set_namelist[nameidx], &ss.set_frames[depth].namelist[nameidx]) != 0 ) - { /* Populate the namelist of the set at the current depth */ - for(i = 0; i <= depth; i++) - name_u8_cpy(&ss.set_frames[depth].namelist[i], &set_namelist[i]); - - /* Alloc set and odat */ - ss.set_frames[depth].odatp = alloc_odat(); - ss.set_frames[depth].setp = alloc_set(); - - /* populate set/odat name and cdat_idx */ - name_u8_cpy(&ss.set_frames[depth].odatp->name, &set_namelist[depth]); - ss.set_frames[depth].setp->cdat_idx = ( *cdat_stackp)->idx; - - /* Insert allocated set and odat into their respective trees if there is a depth - (they have parents) */ - if(depth) - { ss.set_frames[depth].odatp->parent_odatp = ss.set_frames[depth-1].odatp; - if(ss.set_frames[depth-1].setp->num_sets < MAX_SETS) - ss.set_frames[depth-1].setp->set_list[ss.set_frames[depth-1].setp->num_sets++] = ss.set_frames[depth].setp; - else - { printf("you have allocated too many sets in insert_namelist()\n"); - //TODO: EXIT() - } - } - else /* no parent set, so assign to cdat set_list */ - { ss.set_frames[depth].odatp->parent_odatp = NULL; //no parent odat = NULL. - if(curr_cdat_set()->num_sets < MAX_SETS) - curr_cdat_set()->set_list[curr_cdat_set()->num_sets++] = ss.set_frames[depth].setp; - else - { printf("you have allocated too many sets in insert_namelist()\n"); - //TODO: EXIT() - } - } - - - ss.set_frames[depth].num_names = set_numnames; - ss.curr_depth = depth; - - /* Every set has a vdat, but some won't be populated because the namelist that instantiated */ - /* the set might not have a SS statement that populates the models of the vdat. This is ok */ - /* because 1) IR is supposed to be bloated so that binary out isnt 2) this functionality */ - /* preserves the assumptions that insert_framesheet() makes when it calls curr_vdat() */ - alloc_vdat(); - } - - } - - } - - /* Set to 0 to reset for next set_namelist */ - set_numnames = 0; -} - - -/* We create new odats for each map variant that are children of the current odat/set - set their name as the map name, and identify them by marking them as a map. This lets - us distinguish between sibling odats that have the same name because the map of the parent - odat had the same name as another, regular odat. */ -#define CURR_SS_FRAME() (ss.set_frames[ss.curr_depth]) -#define CURR_SS_SETP() (CURR_SS_FRAME().setp) -#define CURR_SS_ODATP() (CURR_SS_FRAME().odatp) -void -insert_map -( struct name* name, int direction, int height, int width, int refid, uint8_t* filepath ) -{ int i; - struct odat* curr_map_odatp; //pointer to odat in odat_buf - struct set* curr_map_setp; //pointer to set in set_buf - struct link* linkp; - - curr_map_odatp = alloc_odat(); - curr_map_setp = alloc_set(); - /* Create a new odat, make its parent be the set. Make a set for mdat, its name should */ - /* be the name of the odat + name of model. That makes a conflict beween odats that are named */ - /* the same thing as the model of a sibling odat that was created from a map. They can have */ - /* same name if the map odat is marked. So mark the map odat. */ - - /* insert parent odat */ - curr_map_odatp->parent_odatp = CURR_SS_ODATP(); - - /* insert into set_list */ - if(CURR_SS_SETP()->num_sets < MAX_SETS) - CURR_SS_SETP()->set_list[CURR_SS_SETP()->num_sets++] = curr_map_setp; - else - { printf("You have allocated to many sets, error in insert_map()\n"); - //TODO: EXIT() - } - - /* indicate that newly created odat is a map */ - curr_map_odatp->ismap = 1; - /* set odat and set name */ - name_u8_cpy(&curr_map_odatp->name, name); - - /* set cdat idx values for both set and odat */ - curr_map_setp->cdat_idx = num_cdats; - - /* Insert map information into the odats map */ - curr_map_odatp->map.height = height; - curr_map_odatp->map.width = width; - u8_stpncpy(curr_map_odatp->map.filepath, filepath, FPATH_MAX); - - - /* Generate refid if needed, put into ref_buf */ - if(!refid) - refid = ss_refid++; - - insert_ref(curr_map_odatp, refid); - - /* If current odatp on stack has a link, then we need to make our own link. just set the vdat_idx */ - if(CURR_SS_ODATP()->vdat_idx == 0) - { linkp = alloc_link(); - linkp->type = CURR_SS_ODATP()->linkp->type; - linkp->dest_odatp = CURR_SS_ODATP(); - linkp->dest_refid = refid; - linkp->link_t.mlink.src_refid = CURR_SS_ODATP()->linkp->link_t.mlink.src_refid; - - /* Copy the animation name of the vlink*/ - name_u8_cpy(&linkp->link_t.vlink.src_animname, &CURR_SS_ODATP()->linkp->link_t.vlink.src_animname); - /* Copy the namelist of the vlink*/ - for(i = 0; i < MAX_DEPTH; i++) - name_u8_cpy(&linkp->link_t.vlink.src_namelist[i], &CURR_SS_ODATP()->linkp->link_t.vlink.src_namelist[i]); - } - else - curr_map_odatp->vdat_idx = CURR_SS_ODATP()->vdat_idx; - -} - - -/* 11/22 Each vdat has a multiple models. Each model has 8 framesheets, one in each - direction, that create a spritesheet. Inserting framesheets into the correct - model is just a matter of checking whether or not the last models name matches - the current one. We can never get a framesheet that is for the same model before - AND after some other model, due to alphasorting of the files in each directory */ -void -insert_framesheet -( struct name* model_name, int direction, int height, int width, int refid, uint8_t* filepath ) -{ struct vdat* curr_vdatp; - struct model* curr_modelp; - static struct name last_model_name[32]; - - curr_vdatp = curr_vdat(); - - /* If the model name changed, that means there are no more - framesheets for that model to be processed, a guaruntee we make - b/c the filenames are alphabetically sorted */ - if(!name_u8_cmp(last_model_name, model_name)) - { if(curr_vdatp->num_models) - curr_vdatp->num_models++; - num_models++; // total number of models - } - - - if(CURR_SS_ODATP()->refid == 0) - { if(!refid) - refid = ss_refid++; - insert_ref(CURR_SS_ODATP(), refid); /* given a odatp and a refid, insert the odatp into the ref_buf. */ - } - else - printf("error: redefining a previously set refid\n"); - - curr_modelp = curr_model(); - - name_u8_cpy(&curr_modelp->name, model_name); - curr_modelp->spritesheet[direction].height = height; - curr_modelp->spritesheet[direction].width = width; - u8_stpncpy(curr_modelp->spritesheet[direction].filepath, filepath, FPATH_MAX); - - name_u8_cpy(last_model_name, model_name); - -} - - -void -insert_mlink -( struct name* src_mapname, int src_refid) -{ struct link* linkp; - int i; - - linkp = alloc_link(); - - /* set type */ - linkp->type = 3; - /* set the name of the src map for the link, if a name exists */ - if(src_mapname) - name_u8_cpy(&linkp->link_t.mlink.src_mapname, src_mapname); - /* Set the source ref id of the link */ - linkp->link_t.mlink.src_refid = src_refid; - - /* Copy the entire namelist of the link, if it exists */ - for(i = 0; i < link_numnames; i--) - { name_u8_cpy(&linkp->link_t.mlink.src_namelist[i], &link_namelist[i]); - name_u8_set(&link_namelist[i], (ucs4_t) 0); - } - link_numnames = 0; - - linkp->dest_odatp = CURR_SS_ODATP();//current odat on set_stack - -} - - -void -insert_link_name -( struct name* name ) -{ - //Push name onto current namelist, set the set_namelist. - name_u8_cpy(&link_namelist[link_numnames++], name); - -} - - -/* Nearly identical to mlink */ -void -insert_vlink -( struct name* src_animname, int src_refid ) -{ struct link* linkp; - int i; - - linkp = alloc_link(); - - /* set type */ - linkp->type = 2; - - /* set the name of the src animname for the link, if a name exists */ - if(src_animname) - name_u8_cpy(&linkp->link_t.vlink.src_animname, src_animname); - - /* Set the source ref id of the link */ - linkp->link_t.mlink.src_refid = src_refid; - - /* Copy the entire namelist of the link, if it exists */ - for(i = 0; i < link_numnames; i++) - { name_u8_cpy(&linkp->link_t.vlink.src_namelist[i], &link_namelist[i]); - name_u8_set(&link_namelist[i], (ucs4_t) 0);//set to null for next link_namelist - } - link_numnames = 0; - - linkp->dest_odatp = CURR_SS_ODATP();//current odat on set_stack - -} - - -/* TODO: Do we really need to store the prev/next pointer? iterating through the - ref_buf could be achieved by iterating until the num_refs anyway. */ -void -insert_ref -( struct odat* odatp, int refid ) -{ struct ref* curr_refp; - struct ref* prev_refp; - - curr_refp = alloc_ref(); - prev_refp = prev_ref(); - - prev_refp->nextref = curr_refp; - curr_refp->lastref = prev_refp; - - curr_refp->odatp = odatp; - curr_refp->refid = refid; - - if(refid % 16) - { POST_ALLOC(); - CURRENT_POST()->refid = refid; - CURRENT_POST()->odatp = odatp; - } - -} - - -void -insert_refid -( int refid ) -{ CURR_SS_ODATP()->refid = refid; -} - - -void -insert_vdat -() -{ struct vdat* curr_vdatp; - - curr_vdatp = curr_vdat(); - - curr_vdatp->creator = CURR_SS_ODATP(); - CURR_SS_ODATP()->vdat_idx = num_vdats; - CURR_SS_ODATP()->vdatp = curr_vdatp; - alloc_vdat(); +struct ir_class +{ struct class_t *parent, *nextchild, *nextsib; + struct set_t *root_set; + uint8_t *name; +} **classes; +struct ir_set +{ struct set_t *parent, *nextchild, *nextsib; + struct class_t *class; + uint8_t *name; + struct framebox_t **sprites; + struct framebox_t **maps; + struct simplex_t **audio; + struct link_t **links; +} **sets; +/* Function-Like Macros */ +#define do_warn() do { \ + } while (0) +#define wprint(str) do { \ + fprintf(stderr, str); \ + do_warn(); \ + } while (0) +#define wprintf(fmt,...) do { \ + fprintf(stderr, fmt, __VA_ARGS__); \ + do_warn(); \ + } while (0) +#define do_error() do { \ + exit(-1); \ + } while (0) +#define eprint(str) do { \ + fprintf(stderr, str); \ + do_error(); \ + } while (0) +#define eprintf(fmt,...) do { \ + fprintf(stderr, fmt, __VA_ARGS__); \ + do_error(); \ + } while (0) + +static +struct ir_class root_class = { .name = &"." }; + +/* Init */ +int ir_init +( void ) +{ return 0; } + +/* Return a pointer to the root class */ +struct ir_class_t* ir_class_root +( void ) +{ return &root_class; } + +/* Add a subclass to a class + Attempts to create a new subclass in the provided class, exiting with an + error if the class already exists +*/ +#define ERR_DUPECLASS "Subclass %s of class %s already exists!", name, *class.name +struct ir_class_t* ir_class_addchild +( struct ir_class_t* class, + uint8_t* name +) +{ struct ir_class_t* iter = *class.nextchild; + if (iter == NULL) + return *class.nextchild = class_alloc(name); + iterate: + if (bytes_identical(*iter.name, name)) + { fprintf(stderr, ERR_DUPECLASS); + exit(-1); + } + if (*iter.nextsib != NULL) + { iter = *iter.nextsib; + goto iterate; + } + return *iter.nextsib = class_alloc(name); + +} + +/* Return a pointer to the parent of the provided class */ +struct ir_class_t* ir_class_parent +( struct ir_class_t* class ) +{ return class.parent; } + +/* Add a set to a class + Attempts to create a new root set in the specified class, exiting with an + error if the set already exists +*/ +#define ERR_DUPESET "Root set %s of class %s already exists!", name, *class.name +struct ir_set_t* ir_class_addset +( struct ir_class_t* class, + uint8_t* name +) +{ struct ir_set_t* iter = *class.root_set; + if (iter == NULL) + return *class.root_set = set_alloc(name); + iterate: + if (bytes_identical(*iter.name, name)) + { fprintf(stderr, ERR_DUPSET); + exit(-1); + } + if (*iter.nextsib != NULL) + { iter = *iter.nextsib; + goto iterate; + } + return *iter.nextsib = set_alloc(name); +} + +struct ir_set_t* ir_set_addchild +( struct ir_set_t* set, + uint8_t* name +) +{ } + +/* Match two null-terminated bytestrings + Return 1 if the two bytestrings are identical, else 0 +*/ +static inline +uint8_t bytes_identical +( uint8_t* stra, + uint8_t* strb +) +{ while (*stra && *strb) + if (*stra++ != *strb++) + return 0; + return *stra == *strb; } diff --git a/src/ir.h b/src/ir.h index 0d271b1..1a7d1a7 100644 --- a/src/ir.h +++ b/src/ir.h @@ -1,16 +1,89 @@ +/*!@file +\brief Intermediate Representation (IR) between Directory Structure and Engine + Input -/*!@file -\brief Intermediate Representation (IR) between Directory Structure and Engine Input \details The IR serves as a storage structure that is populated during the parsing of the input directory structure. After parsing is complete, the IR will be condensed (removed of excess allocated space) and then - output as the input for the engine. In this file we describe the semantic actions - that are called at each step, and the memory buffers that they populate. - See parser.y for the description on how the input grammar is constructed, - and where/when semantic actions are called. - TODO: or just write it here. + output as the input for the engine. In this file we describe the + semantic actions that are called at each step, and the memory buffers + that they populate. See parser.y for the description on how the input + grammar is constructed, and where/when semantic actions are called. + + All input values are duplicated internally and their memory may be + freed. + \author Jordan Lavatai \date Aug 2016 ----------------------------------------------------------------------------*/ +#ifndef _IR_H_ +#define _IR_H_ +#include +enum frame_facing { SFACE, SWFACE, WFACE, NWFACE, NFACE, NEFACE, EFACE, SEFACE, FACING_MAX }; +typedef enum frame_facing ir_facing; +typedef union ir_set_data_t* ir_setdata; +typedef struct ir_set_t* ir_set; +typedef struct ir_class_t* ir_class; +typedef struct ir_setld_t* ir_setld; +typedef struct ir_classld_t* ir_classld; +/* Classes and Sets + Classes are rooted at a special root class, representing the current working + directory at scan-time, named ".". The root class can always be identified + with ir_class_root, and children may be added to it. The add series of + functions will return a reference to the newly created object, which may also + be used the root for further add functions. + + E.G. + ir_class x = ir_class_root(); + x = ir_class_addchild(x, "mychild"); + x = ir_class_addchild(x, "child of mychild"); + Sets, like classes, must be rooted. Unlike classes, sets may be rooted on + other sets, in addition to classes. ir_class_addset will return a set rooted + on the class specified, while ir_set_addchild will return a set rooted on the + specified set. +*/ +ir_class ir_class_root(void); +ir_class ir_class_addchild(ir_class, uint8_t*); +ir_set ir_class_addset(ir_class,uint8_t*); +ir_set ir_set_addchild(ir_set,uint8_t*); +/* Set Data + Each set can contain up to FACING_MAX each of framesheets and mapsheets, one + sheet for each facing, per label. Each set can contain any number of audio + objects, supplied by label. Repeat assignment of conflicting data (e.g. two + SFACE framesheets assigned to the same set and label, or two audio objects + with the same label) causes an internal error. + Each set may also contain any number of link objects, which will be linked in + the order that they are encountered. At link time, repeated assignments of + conflicting data cause data to be silently overwritten for those sets. This + is an intentional side-effect of the linker. + Each setdata may have a path associated with it. If the data depends on the + data of an associated file at that path and no path is provided, the data + will be entered null. +*/ +void ir_set_assign_data(ir_set,ir_setdata); +void ir_set_assign_ref(ir_set,long long); +void ir_data_assign_path(ir_setdata,uint8_t*); +ir_setdata ir_framesheet(uint8_t*,ir_facing,int,int); +ir_setdata ir_mapsheet(uint8_t*,ir_facing,int,int); +ir_setdata ir_audio(uint8_t*); +ir_setdata ir_link_odat(ir_setld); +ir_setdata ir_link_vdat(ir_setld,uint8_t*); +ir_setdata ir_link_mdat(ir_setld,uint8_t*); +ir_setdata ir_link_adat(ir_setld,uint8_t*); +/* Reference Linking Data + Create linking data to sets or classes that will be resolved at a later + stage. Class references can be created from an ir_class object, if + available, or from the root class. Set references can be created from a + 64-bit integer ID, or from a class linking data and a child name. Once + created, both Class and Set link data can traverse children, specified by + name, which will be resolved at the linking stage as well. +*/ +ir_classld ir_classld_from_class(ir_class); +ir_classld ir_classld_from_root(void); +ir_classld ir_classld_addchild(ir_classld,uint8_t*); +ir_setld ir_setld_from_ref(long long); +ir_setld ir_setld_from_classld(ir_classld,uint8_t*); +ir_setld ir_setld_addchild(ir_setld,uint8_t*); +#endif //_IR_H_ diff --git a/src/parser.y b/src/parser.y index 95a47cf..c1f15f4 100644 --- a/src/parser.y +++ b/src/parser.y @@ -8,159 +8,174 @@ #include #include #include - extern int lexer_init(); //? - extern int lexer(); //? - extern void pop_cdat(void); - extern void push_cdat(uint8_t*); - extern void insert_vdat(void); - extern void insert_refid(int); - extern void insert_set_name(uint8_t*); - extern void insert_set_namelist(uint8_t*); - extern void insert_link_name(uint8_t*); - extern void insert_map(uint8_t*,int, int, int, int, uint8_t*); - extern void insert_mlink(uint8_t*, int); - extern void insert_vlink(uint8_t*, int); - extern void insert_framesheet(uint8_t* ,int, int, int,int, uint8_t*); - - #define yylex lexer - - - void yyerror(); + #include "ir.h" + + struct frame_spec_t { enum facing d; int w, h; }; + + extern long sys_pagesize; + extern int lexer(); + static void yyerror(char const*); + /* Stack-based class handler */ + static ir_class *class_stack, *csp; + static size_t class_stack_size; + static ir_class class_stack_init(void); + #define class_stack_pop() (*--csp) + static ir_class class_stack_push(ir_class); + + #define yylex lexer + #define yyclass (*csp) + #define yyclassld (ir_classld_from_class(yyclass)) %} %define parse.error verbose %define lr.type ielr - +%define api.pure full +%define api.push-pull push %union { - long long ref; - int val; - uint8_t* str; - void *voidp; + long long ref; + int val; + enum facing face; + uint8_t* str; + ir_class class; + ir_set set; + ir_setld ld; + ir_setdata data; + struct frame_spec_t frame_spec; } - - //operators -%token CLOPEN // ( -%token CLCLOSE // ) -%token MOPEN // ~ -%token HB -%token ROOT -%token SS -%token LINK //# -%token SCLOSE -%token CHILD -//terminals -%token NUM -%token PATH -%token REF -%token HEIGHT -%token WIDTH -%token D -%token NAME - /* Syntax Directed Translation Scheme of the APC grammar */ - -/* Rules */ +/* Operators */ +%token CLOPEN //( +%token CLCLOSE //) +%token MAP //~ +%token AUDIO //AUDIO +%token SS //SS +%token LINK //# +/* Terminals */ +%token NUM +%token PATH +%token REF +%token FACING +%token NAME +/* Types */ +%type data_spec +%type set_spec +%type set_ld set_link +%type frame_spec +/* Init */ +%initial-action { class_stack_init(); } %% -cdat_buf: -class_block -; - -class: -NAME CLOPEN {push_cdat($1);} class_block CLCLOSE {pop_cdat();}; +/* Syntax Directed Translation Scheme of the APC grammar */ +progn: + class_list +| class_list statement_list +| statement_list ; class_list: -class_list class + class_list class | class ; -class_block: -class_list -| class_list statement_list -| statement_list +class: + NAME CLOPEN { class_stack_push(ir_class_addchild(yyclass, $1)); } + progn + CLCLOSE { class_stack_pop(); } ; statement_list: -statement_list statement -| statement + statement_list statement +| statement ; statement: -vdat_statement -| map_statement -| ref_statement -| olink -; - -ref_statement: -set_namelist REF {insert_refid($2);}; + set_spec data_spec REF PATH { ir_data_assign_path($2,$4); ir_set_assign_data($1,$2); ir_set_assign_ref($1,$3); } +| set_spec data_spec PATH { ir_data_assign_path($2,$3); ir_set_assign_data($1,$2); } +| set_spec REF PATH { ir_set_assign_ref($1,$2); } ; -link_namelist: -link_namelist NAME {insert_link_name($2);}; -| NAME {}; +data_spec: + SS NAME frame_spec { $$ = ir_framesheet($2,$3.d,$3.w,$3.h); } +| MAP NAME frame_spec { $$ = ir_mapsheet($2,$3.d,$3.w,$3.h); } +| AUDIO NAME { $$ = ir_audio($2); } +| LINK set_ld { $$ = ir_link_odat($2); } +| LINK set_ld MAP { $$ = ir_link_mdat($2,NULL); } +| LINK set_ld MAP NAME { $$ = ir_link_mdat($2,$4); } +| LINK set_ld SS { $$ = ir_link_vdat($2,NULL); } +| LINK set_ld SS NAME { $$ = ir_link_vdat($2,$4); } +| LINK set_ld AUDIO { $$ = ir_link_adat($2,NULL); } +| LINK set_ld AUDIO NAME { $$ = ir_link_adat($2,$4); } ; - -set_namelist: -set_namelist NAME {insert_set_name($2);}; -| NAME {insert_set_namelist($1);}; -; - -map_statement: -set_namelist MOPEN map -| set_namelist MOPEN mlink -; - -map: -NAME NUM NUM PATH {insert_map($1, 0, $3, 0, 0, $4);}; -| NAME PATH {insert_map($1, 0, 0, 0, 0, $2);}; -| NAME D PATH {insert_map($1, $2, 0, 0, 0, $3);}; -| NAME D NUM NUM PATH {insert_map($1, $2, $3, $4, 0, $5);}; -| NAME NUM NUM REF PATH {insert_map($1, 0, $2, $3, $4, $5);}; -| NAME REF PATH {insert_map($1, 0, 0, 0, $2, $3);}; -| NAME D REF PATH {insert_map($1, $2, 0, 0, $3, $4);}; -| NAME D NUM NUM REF PATH {insert_map($1, $2, $3, $4, $5, $6);}; -; - -//shift list_namelist name > reduce mlink -mlink: -MOPEN LINK NAME LINK link_namelist PATH {insert_mlink($3, 0); }; -| MOPEN LINK link_namelist PATH {insert_mlink(NULL, 0); }; -| MOPEN LINK REF PATH {insert_mlink(NULL, $3); }; -| MOPEN LINK NAME LINK REF PATH {insert_mlink($3,$5); }; -; - -//shift list_namelist name > reduce vlink -vlink: -LINK NAME LINK link_namelist PATH {insert_vlink($2, 0); }; -| LINK link_namelist PATH {insert_vlink(NULL, 0);}; -| LINK REF PATH {insert_vlink(NULL, $2);};//vdat of ref -| LINK NAME LINK REF PATH {insert_vlink($2, $4);};//modelname of ref +set_spec: + set_spec NAME { $$ = ir_set_addchild($1,$2); } +| NAME { $$ = ir_class_addset(yyclass,$1); } ; - -olink: -set_namelist MOPEN REF +set_link: + set_link NAME { $$ = ir_setld_addchild($1,$2); } +| NAME { $$ = ir_setld_from_classld(yyclassld,$1) } ; -vdat_statement: -set_namelist SS spritesheet_statement -| set_namelist SS vlink +set_ld: + set_link { $$ = $1; } +| REF { $$ = ir_setld_from_ref($1); } ; -spritesheet_statement: -NAME D HEIGHT WIDTH PATH {insert_framesheet($1, $2, $3, $4, 0, $5);}; -| NAME D PATH {insert_framesheet($1, $2, 0, 0, 0, $3);}; -| NAME HEIGHT WIDTH PATH {insert_framesheet($1, 0, $2, $3, 0, $4);}; -| NAME PATH {insert_framesheet($1, 0, 0, 0, 0, $2);}; -| NAME D HEIGHT WIDTH REF PATH {insert_framesheet($1, $2, $3, $4, $5, $6);}; -| NAME D REF PATH {insert_framesheet($1, $2, 0, 0, $3, $4);}; -| NAME HEIGHT WIDTH REF PATH {insert_framesheet($1, 0, $2, $3, $4, $5);}; -| NAME REF PATH {insert_framesheet($1, 0, 0, 0, $2, $3);}; +frame_spec: + NUM NUM { $$ = (struct frame_spec_t) {SFACE,$1,$2}; } +| FACING { $$ = (struct frame_spec_t) {$1,0,0}; } +| FACING NUM NUM { $$ = (struct frame_spec_t) {$1,$2,$3}; } ; %% -void -yyerror (char const *s) -{ fprintf(stderr, "%s\n", s); +#define ERR_ALLOC "memory allocation error\n" + +/* print to stderr */ +static +void yyerror +( char const *s ) +{ fprintf(stderr, "%s\n", s); } + +/* Initialize the class stack + If the class_stack hasn't been allocated yet, allocates a page for pointers + to be stored in. Initializes class stack pointer, and inserts the root class + from IR + Returns the root class given by IR. +*/ +static +ir_class class_stack_init +( void ) +{ if (class_stack == NULL) + { class_stack_size = (size_t) sys_pagesize; + class_stack = (ir_class*) malloc(class_stack_size); + if (class_stack == NULL) + { yyerror(ERR_MEM); + exit(1); + } + } + csp = class_stack; + return class_stack_push(ir_class_root()); +} + +/* Add a Class to the Stack + Allocated in page-sized chunks, potentially infinite depth is supported. + Returns the input class. +*/ +static +ir_class class_stack_push +#define class_size (sizeof(*class_stack)) +( ir_class class ) +{ size_t class_stack_len = csp - class_stack; + ir_class* new_class_stack; + if ((class_stack_len * class_size + class_size) > class_stack_size) + { class_stack_size += (size_t) sys_pagesize; + new_class_stack = (ir_class*) realloc(class_stack, class_stack_size); + if (new_class_stack == NULL) + { free(class_stack); //realloc failure does not free class_stack + yyerror("realloc " ERR_MEM); + exit(1); + } + class_stack = new_class_stack; + csp = class_stack + class_stack_len; + } + return (*csp++ = class); } diff --git a/src/scanner.c b/src/scanner.c index 5c06a4e..14266ca 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -223,7 +223,11 @@ int dredge_current_depth struct dirent* direntp; DL_CD_INIT(); scan_next: - if ((direntp = readdir(cwd)) != NULL) + errno = 0; + direntp = readdir(cwd); + if (errno) + return -1; + if (direntp != NULL) { switch (direntp->d_type) { case DT_REG: DPS_PUSH(direntp); @@ -239,8 +243,6 @@ int dredge_current_depth goto scan_next; } } - if (errno) - return -1; qsort(lexer_direntpa, DPS_LEN(), sizeof direntp, (qcomp)alphasort); return DPS_LEN(); } -- 2.18.0