From d1f04810bdfeca75e5956b7ad3356db15f02327f Mon Sep 17 00:00:00 2001 From: Marrub Date: Wed, 20 Sep 2017 11:42:57 -0400 Subject: [PATCH] Add initial code --- .gitignore | 8 + Makefile | 37 +++ bin/dummy | 1 + codedefs/dummy | 1 + objdefs.dod | 4 + objdefs/player.dod | 15 ++ src/g_objdef.c | 611 +++++++++++++++++++++++++++++++++++++++++++++ src/g_object.h | 65 +++++ src/m_darray.h | 23 ++ src/m_str.c | 52 ++++ src/m_str.h | 16 ++ src/m_token.c | 148 +++++++++++ src/m_token.h | 100 ++++++++ src/m_types.h | 31 +++ src/main.c | 74 ++++++ 15 files changed, 1186 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 bin/dummy create mode 100644 codedefs/dummy create mode 100644 objdefs.dod create mode 100644 objdefs/player.dod create mode 100644 src/g_objdef.c create mode 100644 src/g_object.h create mode 100644 src/m_darray.h create mode 100644 src/m_str.c create mode 100644 src/m_str.h create mode 100644 src/m_token.c create mode 100644 src/m_token.h create mode 100644 src/m_types.h create mode 100644 src/main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3d10cc8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +bin/*.ir +codedefs/*.bin +src_crap +src_oldtest +doc +sounds +sprites +textures diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..004094c --- /dev/null +++ b/Makefile @@ -0,0 +1,37 @@ +## Copyright © 2017 Project Golan, all rights reserved. +CC=gdcc-cc +LD=gdcc-ld +MAKELIB=gdcc-makelib + +BIN=codedefs +SRC=src +INC=inc +IR=bin + +TARGET=--bc-target=Doominati +LFLAGS=$(TARGET) +CFLAGS=$(TARGET) --alloc-Aut=4194304 -c + +MAIN_SOURCES=$(wildcard $(SRC)/*.c) +MAIN_HEADERS=$(wildcard $(SRC)/*.h) +MAIN_OUTPUT=$(MAIN_SOURCES:$(SRC)/%.c=$(IR)/%.ir) +MAIN_BINARY=$(BIN)/影響の目.bin + +all: $(BIN)/stdlib.bin $(MAIN_BINARY) + +$(BIN)/stdlib.bin: $(IR)/libc.ir $(IR)/libGDCC.ir + $(LD) $(LFLAGS) -o $@ $^ + +$(MAIN_BINARY): $(MAIN_OUTPUT) + $(LD) $(LFLAGS) -o $@ $^ + +$(IR)/%.ir: $(SRC)/%.c $(MAIN_HEADERS) + $(CC) $(CFLAGS) -o $@ $< + +$(IR)/libc.ir: + $(MAKELIB) $(TARGET) -c -o $@ libc + +$(IR)/libGDCC.ir: + $(MAKELIB) $(TARGET) -c -o $@ libGDCC + +## EOF diff --git a/bin/dummy b/bin/dummy new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/bin/dummy @@ -0,0 +1 @@ + diff --git a/codedefs/dummy b/codedefs/dummy new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/codedefs/dummy @@ -0,0 +1 @@ + diff --git a/objdefs.dod b/objdefs.dod new file mode 100644 index 0000000..ea8569c --- /dev/null +++ b/objdefs.dod @@ -0,0 +1,4 @@ +// Copyright © 2017 Project Golan, all rights reserved. +include "objdefs/player.dod" + +// EOF diff --git a/objdefs/player.dod b/objdefs/player.dod new file mode 100644 index 0000000..39e4a74 --- /dev/null +++ b/objdefs/player.dod @@ -0,0 +1,15 @@ +// Copyright © 2017 Project Golan, all rights reserved. +entity Shootable +{ + health 1 +} + +entity Player < Shootable +{ + task G_Player_Think + size 3 + drawsize 16 + sprite "@sprites/particle3.png" +} + +// EOF diff --git a/src/g_objdef.c b/src/g_objdef.c new file mode 100644 index 0000000..e428fda --- /dev/null +++ b/src/g_objdef.c @@ -0,0 +1,611 @@ +// Copyright © 2017 Project Golan, all rights reserved. +#include "g_object.h" +#include "m_token.h" +#include "m_str.h" +#include "m_darray.h" + +#include +#include + +#include +#include +#include + +#define G_dodTokBeg (4) +#define G_dodTokEnd (10) + +#define G_ofmap_GetKey(o) ( (o)->name) +#define G_ofmap_GetNext(o) (&(o)->next) +#define G_ofmap_GetPrev(o) (&(o)->prev) +#define G_ofmap_HashObj(o) ( (o)->keyhash) +#define G_ofmap_HashKey(k) (M_StrHash(k)) +#define G_ofmap_KeyCmp(l, r) (strcmp(l, r)) + +#define G_etmap_GetKey(o) ( (o)->name) +#define G_etmap_GetNext(o) (&(o)->next) +#define G_etmap_GetPrev(o) (&(o)->prev) +#define G_etmap_HashObj(o) ( (o)->keyhash) +#define G_etmap_HashKey(k) (M_StrHash(k)) +#define G_etmap_KeyCmp(l, r) (strcmp(l, r)) + +#define G_frmap_GetKey(o) ( (o)->name) +#define G_frmap_GetNext(o) (&(o)->next) +#define G_frmap_GetPrev(o) (&(o)->prev) +#define G_frmap_HashObj(o) ( (o)->keyhash) +#define G_frmap_HashKey(k) (M_StrHash(k)) +#define G_frmap_KeyCmp(l, r) (strcmp(l, r)) + +#define G_anmap_GetKey(o) ( (o)->name) +#define G_anmap_GetNext(o) (&(o)->next) +#define G_anmap_GetPrev(o) (&(o)->prev) +#define G_anmap_HashObj(o) ( (o)->keyhash) +#define G_anmap_HashKey(k) (M_StrHash(k)) +#define G_anmap_KeyCmp(l, r) (strcmp(l, r)) + +#define G_anims_GetKey(o) ( (o)->name) +#define G_anims_GetNext(o) (&(o)->next) +#define G_anims_GetPrev(o) (&(o)->prev) +#define G_anims_HashObj(o) ( (o)->keyhash) +#define G_anims_HashKey(k) (M_StrHash(k)) +#define G_anims_KeyCmp(l, r) (strcmp(l, r)) + +// Static Functions ----------------------------------------------------------| + +_Noreturn static void G_ObjDef_throw (struct G_dodst *st, char const *emsg); +static M_token *G_ObjDef_getToken(struct G_dodst *st); +static M_token *G_ObjDef_unget (struct G_dodst *st); +static M_token *G_ObjDef_reget (struct G_dodst *st); +static bool G_ObjDef_drop (struct G_dodst *st, M_tokty t); +[[__optional_args(1)]] +static M_token *G_ObjDef_expect (struct G_dodst *st, M_tokty t, char const *exp); +[[__optional_args(1)]] +static struct G_odarg G_ObjDef_getArgs (struct G_dodst *st, char const *arg); + +// Types ---------------------------------------------------------------------| + +GDCC_HashMap_Decl(G_ofmap, char const *, struct G_ofdcl) +GDCC_HashMap_Decl(G_etmap, char const *, struct G_etdcl) +GDCC_HashMap_Decl(G_frmap, char const *, struct G_frdcl) +GDCC_HashMap_Decl(G_anmap, char const *, struct G_andcl) +GDCC_HashMap_Decl(G_anims, char const *, struct G_manim) + +typedef struct G_dodst +{ + __prop throw {call: G_ObjDef_throw (this)} + __prop getToken {call: G_ObjDef_getToken(this)} + __prop unget {call: G_ObjDef_unget (this)} + __prop drop {call: G_ObjDef_drop (this)} + __prop expect {call: G_ObjDef_expect (this)} + __prop getArgs {call: G_ObjDef_getArgs (this)} + __prop reget {call: G_ObjDef_reget (this)} + + jmp_buf ejmp; + int lines; + char const *fname; + FILE *fp; + int tpos, tend; + M_token toks[G_dodTokEnd]; +} G_dodst; + +typedef union G_odprm +{ + mword u; + integ i; + fixed k; + lfrac r; +} G_odprm; + +typedef struct G_odarg +{ + G_odprm argv[8]; + int argc; +} G_odarg; + +typedef struct G_ofdcl +{ + DGE_CallbackType fptr; + char const *name; + size_t keyhash; + struct G_ofdcl *next, **prev; +} G_ofdcl; + +typedef struct G_etdcl +{ + G_entty type; + G_anims anim; + M_Vec_decl(struct G_manim, anims); + + char name[32]; + size_t keyhash; + struct G_etdcl *next, **prev; +} G_etdcl; + +typedef struct G_frdcl +{ + M_texid sprite; + char name[32]; + size_t keyhash; + struct G_frdcl *next, **prev; +} G_frdcl; + +typedef struct G_andcl +{ + M_Vec_decl(G_frame, frame); + char name[32]; + size_t keyhash; + struct G_andcl *next, **prev; +} G_andcl; + +typedef struct G_manim +{ + G_anima anim; + char name[32]; + size_t keyhash; + struct G_manim *next, **prev; +} G_manim; + +// Static Objects ------------------------------------------------------------| + +static G_ofmap G_objfuncs; +static G_etmap G_enttypes; +static G_frmap G_frametab; +static G_anmap G_animsmap; + +M_Vec_defn(G_ofdcl, G_ofvec, static); +M_Vec_defn(G_etdcl, G_etvec, static); +M_Vec_defn(G_frdcl, G_frvec, static); +M_Vec_defn(G_andcl, G_anvec, static); + +// Static Functions ----------------------------------------------------------| + +GDCC_HashMap_Defn(G_ofmap, char const *, G_ofdcl) +GDCC_HashMap_Defn(G_etmap, char const *, G_etdcl) +GDCC_HashMap_Defn(G_frmap, char const *, G_frdcl) +GDCC_HashMap_Defn(G_anmap, char const *, G_andcl) +GDCC_HashMap_Defn(G_anims, char const *, G_manim) + +// +// G_ObjDef_throw +// +_Noreturn static void G_ObjDef_throw(G_dodst *st, char const *emsg) +{ + fprintf(stderr, "ObjDef (%s:%i): %s\n", st->fname, st->reget()->line, emsg); + longjmp(st->ejmp, 1); +} + +// +// G_ObjDef_getToken +// +static M_token *G_ObjDef_getToken(G_dodst *st) +{ + if(++st->tpos < st->tend) + return &st->toks[st->tpos]; + + memmove(&st->toks[0], &st->toks[st->tend - G_dodTokBeg], + sizeof(M_token) * G_dodTokBeg); + + for(st->tpos = st->tend = G_dodTokBeg; st->tend < G_dodTokEnd; st->tend++) + { + skip: + M_Tk_Parse(st->fp, &st->toks[st->tend]); + st->toks[st->tend].line = st->lines; + + switch(st->toks[st->tend].type) { + default: break; + case tok_eof: goto done; + case tok_lnend: st->lines++; + case tok_cmtlin: goto skip; + } + } + + /* + for(int i = 0; i < st->tend; i++) + printf("%i: %s%s\n", st->toks[i].type, st->toks[i].text, i == st->tpos ? " <-- cursor is here" : ""); + */ + +done: + return &st->toks[st->tpos]; +} + +// +// G_ObjDef_unget +// +static M_token *G_ObjDef_unget(G_dodst *st) +{ + return &st->toks[st->tpos--]; +} + +// +// G_ObjDef_reget +// +static M_token *G_ObjDef_reget(G_dodst *st) +{ + return &st->toks[st->tpos]; +} + +// +// G_ObjDef_drop +// +static bool G_ObjDef_drop(G_dodst *st, M_tokty t) +{ + if(st->getToken()->type != t) { + st->unget(); + return false; + } else { + return true; + } +} + +// +// G_ObjDef_expect +// +static M_token *G_ObjDef_expect(G_dodst *st, M_tokty t, char const *exp) +{ + M_token *tok; + if((tok = st->getToken())->type != t) { + if(exp) st->throw(M_StrFmt("expected %s", exp)); + else st->throw("unexpected token"); + } + return tok; +} + +// +// G_ObjDef_getArgs +// +[[__optional_args(1)]] +static G_odarg G_ObjDef_getArgs(G_dodst *st, char const *arg) +{ + G_odarg a = {}; + bool done = false; + int i = 0; + + for(;;) + { + char ch = arg[i++]; + + if(!done && (arg[i] == '\0' || arg[i] == '|')) + done = true; + + switch(ch) + { + #define CaseN(c, t, f, ...) \ + case c: \ + a.argv[a.argc++].t = \ + f(st->expect(tok_number, "number")->text, __VA_ARGS__); \ + break + CaseN('u', u, strtoui, NULL, 0); + CaseN('i', i, strtoi, NULL, 0); + CaseN('k', k, strtofxhk, NULL); + CaseN('r', r, strtofxk, NULL); + // TODO: get david to implement fracts + //CaseN('r', r, strtofxlr, NULL); + #undef CaseN + case '|': done = true; continue; + case '\0': st->throw("too many arguments"); + default: st->throw("unexpected argument type"); + } + + if(!st->drop(tok_comma)) break; + } + + if(!done) + st->throw("not enough arguments"); + + return a; +} + +// +// G_ObjDef_getEntAnim +// +static void G_ObjDef_getEntAnim(G_dodst *st, G_etdcl *decl) +{ + char alias[M_countof(decl->name)]; + + M_strbufcpy(alias, st->expect(tok_identi, "alias name")->text); + st->expect(tok_eq, "'='"); + + G_andcl *an = G_animsmap.find(st->expect(tok_identi, "anim name")->text); + if(an == NULL) st->throw("anim not defined"); + if(decl->anim.find(alias)) st->throw("alias redefinition"); + + M_Vec_grow(decl->anims, 1); + G_manim *anim = &decl->animsV[decl->animsC++]; + M_strbufcpy(anim->name, alias); + anim->keyhash = M_StrHash(anim->name); + anim->anim = (G_anima){an->frameV, an->frameC}; + decl->anim.insert(anim); +} + +// +// G_ObjDef_getEntProp +// +static void G_ObjDef_getEntProp(G_dodst *st, G_entty *type, char const *id) +{ + if(strcmp(id, "task") == 0) + { + G_ofdcl *fn = G_objfuncs.find(st->expect(tok_identi, "function")->text); + if(!fn) st->throw("invalid function name"); + type->task = fn->fptr; + } + else if(strcmp(id, "size") == 0) + { + G_odarg a = st->getArgs("k|kk"); + if(a.argc == 1) { + type->sx = type->sy = a.argv[0].k; + } else { + type->sx = a.argv[0].k; + type->sy = a.argv[1].k; + if(a.argc > 2) type->sz = a.argv[2].k; + } + } + else if(strcmp(id, "drawsize") == 0) + { + G_odarg a = st->getArgs("k|k"); + if(a.argc == 1) { + type->rsx = type->rsy = a.argv[0].k; + } else { + type->rsx = a.argv[0].k; + type->rsy = a.argv[1].k; + } + } + else if(strcmp(id, "sprite") == 0) + { + type->sprite = DGE_GetTexture( + M_StrCreate(st->expect(tok_string, "sprite name")->text)); + } + + // TODO: change this when access through rvalues is fixed + #define Prop(name, t) \ + else if(strcmp(id, #name) == 0) \ + __with(G_odarg a = st->getArgs(#t);) type->name = a.argv[0].t + Prop(health, i); + Prop(friction, k); + Prop(mass, k); + #undef Prop + + else + st->throw("unknown identifier in entity definition"); +} + +// +// G_ObjDef_getFrameSprite +// +static M_texid G_ObjDef_getFrameSprite(char const *fmt, char frame, int i) +{ + M_Vec_defn(char, buf); + + for(; *fmt; fmt++) + { + if(*fmt != '%') {M_Vec_grow(buf, 1); bufV[bufC++] = *fmt; continue;} + + switch(*++fmt) + { + default: + case '%': M_Vec_grow(buf, 1); bufV[bufC++] = *fmt; break; + case 'c': M_Vec_grow(buf, 1); bufV[bufC++] = frame; break; + case 'i': + M_Vec_grow(buf, 20); + bufC += snprintf(&bufV[bufC], 20, "%i", i); + break; + } + } + + if(!bufV) return 0; + + M_texid id = DGE_GetTexture(DGE_String_Create(bufV, bufC)); + free(bufV); + return id; +} + +// +// G_ObjDef_parseFrameDef +// +static void G_ObjDef_parseFrameDef(G_dodst *st) +{ + char name[32], frame[32], fmt[32]; + M_strbufcpy(name, st->expect(tok_identi, "name")->text); + M_strbufcpy(frame, st->expect(tok_identi, "frames")->text); + M_strbufcpy(fmt, st->expect(tok_string, "format")->text); + + for(int i = 0; frame[i]; i++) + { + if(frame[i] < 'A' || frame[i] > 'Z') + st->throw("invalid frame"); + + char const *key = M_StrFmt("%s%c", name, frame[i]); + G_frdcl *decl = G_frametab.find(key); + + if(!decl) + { + M_Vec_grow(G_frvec, 1); + *(decl = &G_frvecV[G_frvecC++]) = (G_frdcl){}; + M_strbufcpy(decl->name, key); + decl->keyhash = M_StrHash(decl->name); + G_frametab.insert(decl); + } + + decl->sprite = G_ObjDef_getFrameSprite(fmt, 'A' + i, i + 1); + } +} + +// +// G_ObjDef_parseAnim +// +static void G_ObjDef_parseAnim(G_dodst *st, G_andcl *decl) +{ + char name[32], frames[32]; + M_strbufcpy(name, st->expect(tok_identi, "name")->text); + M_strbufcpy(frames, st->expect(tok_identi, "frame")->text); + int time = strtoi(st->expect(tok_number, "time")->text, NULL, 0); + + M_Vec_growN(decl->frame, strlen(frames), 0); + for(char const *frame = frames; *frame; frame++) { + char *key = M_StrFmt("%s%c", name, *frame); + G_frdcl *fr = G_frametab.find(key); + if(!fr) st->throw(M_StrFmt("undefined frame '%s'", key)); + decl->frameV[decl->frameC++] = (G_frame){time, fr->sprite}; + } +} + +// +// G_ObjDef_parseAnimDef +// +static void G_ObjDef_parseAnimDef(G_dodst *st) +{ + bool ins = true; + G_andcl *decl; + + __with(char const *name = st->expect(tok_identi, "anim name")->text;) + { + if((decl = G_animsmap.find(name)) == NULL) { + M_Vec_grow(G_anvec, 1); + *(decl = &G_anvecV[G_anvecC++]) = (G_andcl){}; + M_strbufcpy(decl->name, name); + } else { + ins = false; + } + } + + st->expect(tok_braceo, "'{'"); + + while(!st->drop(tok_bracec)) + G_ObjDef_parseAnim(st, decl); + + if(ins) { + decl->keyhash = M_StrHash(decl->name); + G_animsmap.insert(decl); + } +} + +// +// G_ObjDef_parseEntDef +// +static void G_ObjDef_parseEntDef(G_dodst *st) +{ + bool ins = true; + G_etdcl *decl; + + __with(char const *name = st->expect(tok_identi, "entity name")->text;) + { + if((decl = G_enttypes.find(name)) == NULL) { + M_Vec_grow(G_etvec, 1); + *(decl = &G_etvecV[G_etvecC++]) = (G_etdcl){}; + M_strbufcpy(decl->name, name); + G_anims_ctor(&decl->anim, 8, 8); + } else { + ins = false; + } + } + + if(st->drop(tok_lt)) { + G_etdcl *base = + G_enttypes.find(st->expect(tok_identi, "base entity name")->text); + if(!base) st->throw("base type not found"); + decl->type = base->type; + } + + st->expect(tok_braceo, "'{'"); + + for(M_token *tok; (tok = st->getToken())->type != tok_bracec;) + switch(tok->type) + { + case tok_identi: + if(strcmp(tok->text, "anim") == 0) + G_ObjDef_getEntAnim(st, decl); + else + G_ObjDef_getEntProp(st, &decl->type, tok->text); + break; + case tok_semico: + continue; + default: + st->throw("expected '}'"); + } + + if(ins) { + decl->keyhash = M_StrHash(decl->name); + G_enttypes.insert(decl); + } +} + +// Extern Functions ----------------------------------------------------------| + +// +// G_ObjDef_Init +// +void G_ObjDef_Init(void) +{ + G_ofmap_ctor(&G_objfuncs, 16, 16); + G_etmap_ctor(&G_enttypes, 16, 16); + G_frmap_ctor(&G_frametab, 16, 16); + G_anmap_ctor(&G_animsmap, 16, 16); +} + +// +// G_ObjDef_Load +// +void G_ObjDef_Load(char const *fname) +{ + G_dodst st = {.fp = fopen(fname, "r"), .fname = fname, .lines = 1}; + + if(!st.fp) { + fprintf(stderr, "ObjDef: couldn't open file '%s'\n", fname); + goto done; + } + + if(setjmp(st.ejmp) == 1) + goto done; + + for(M_token *tok; (tok = st.getToken())->type != tok_eof;) + switch(tok->type) + { + case tok_identi: + if(strcmp(tok->text, "entity") == 0) + G_ObjDef_parseEntDef(&st); + else if(strcmp(tok->text, "anim") == 0) + G_ObjDef_parseAnimDef(&st); + else if(strcmp(tok->text, "frame") == 0) + G_ObjDef_parseFrameDef(&st); + else if(strcmp(tok->text, "include") == 0) + G_ObjDef_Load(st.expect(tok_string, "string")->text); + else + st.throw("unknown identifier in toplevel"); + continue; + default: + st.throw("expected toplevel definition"); + } + + printf("ObjDef: '%s' loaded.\n", fname); + +done: + fclose(st.fp); +} + +// +// G_ObjDef_LoadFunc +// +void G_ObjDef_LoadFunc(char const *name, DGE_CallbackType fptr) +{ + M_Vec_grow(G_ofvec, 1); + G_ofvecV[G_ofvecC] = (G_ofdcl){fptr, name, M_StrHash(name)}; + G_objfuncs.insert(&G_ofvecV[G_ofvecC++]); +} + +// +// G_ObjDef_GetType +// +G_entty const *G_ObjDef_GetType(char const *name) +{ + G_etdcl const *decl = G_enttypes.find(name); + return decl ? &decl->type : NULL; +} + +// +// G_ObjDef_GetAnim +// +G_anima const *G_ObjDef_GetAnim(G_entty const *type, char const *name) +{ + G_manim *anim = ((G_etdcl *)type)->anim.find(name); + return anim ? &anim->anim : NULL; +} + +// EOF diff --git a/src/g_object.h b/src/g_object.h new file mode 100644 index 0000000..4d511b0 --- /dev/null +++ b/src/g_object.h @@ -0,0 +1,65 @@ +// Copyright © 2017 Project Golan, all rights reserved. +#ifndef g_object_h +#define g_object_h + +#include "m_types.h" + +#include +#include + +#include + +#define G_ObjDef_setupEntity(type, th) \ + do { \ + (th).sprite = (type)->sprite; \ + (th).health = (type)->health; \ + (th).friction = (type)->friction; \ + (th).mass = (type)->mass; \ + (th).rsx = (type)->rsx; \ + (th).rsy = (type)->rsy; \ + (th).sx = (type)->sx; \ + (th).sy = (type)->sy; \ + (th).sz = (type)->sz; \ + } while(0) + +#define G_ObjDef_createTask(type, ...) \ + (DGE_Task_Create(0, (type)->task, __VA_ARGS__)) + +#define G_ObjDef_loadFunc(fn) G_ObjDef_LoadFunc(#fn, (DGE_CallbackType)fn) + +// Extern Functions ----------------------------------------------------------| + +void G_ObjDef_Init(void); +void G_ObjDef_Load(char const *fname); +void G_ObjDef_LoadFunc(char const *name, DGE_CallbackType fptr); +struct G_entty const *G_ObjDef_GetType(char const *name); +struct G_anima const *G_ObjDef_GetAnim(struct G_entty const *type, char const *name); + +// Types ---------------------------------------------------------------------| + +typedef struct G_frame // Frame +{ + integ time; + M_texid sprite; +} G_frame; + +typedef struct G_anima // Animation +{ + G_frame *frame; + msize count; +} G_anima; + +typedef struct G_entty // Entity Type +{ + __prop getAnim {call: G_ObjDef_GetAnim(this)} + + M_texid sprite; + integ health; + lfrac friction; + fixed mass; + fixed rsx, rsy; + fixed sx, sy, sz; + DGE_CallbackType task; +} G_entty; + +#endif diff --git a/src/m_darray.h b/src/m_darray.h new file mode 100644 index 0000000..8deea5e --- /dev/null +++ b/src/m_darray.h @@ -0,0 +1,23 @@ +// Copyright © 2017 Project Golan, all rights reserved. +#ifndef m_darray_h +#define m_darray_h + +#define M_Vec_defn(type, name, ...) \ + __VA_ARGS__ type *name##V = NULL; \ + __VA_ARGS__ size_t name##C = 0, name##S = 0 + +#define M_Vec_decl(type, name, ...) \ + __VA_ARGS__ type *name##V; \ + __VA_ARGS__ size_t name##C, name##S + +#define M_Vec_growN(vec, n, g) \ + do { \ + if((vec##C) + (n) > (vec##S)) { \ + (vec##S) += (n) + (g); \ + (vec##V) = realloc((vec##V), sizeof(*(vec##V)) * (vec##S)); \ + } \ + } while(0) + +#define M_Vec_grow(vec, n) M_Vec_growN(vec, n, 8) + +#endif diff --git a/src/m_str.c b/src/m_str.c new file mode 100644 index 0000000..56dc7c6 --- /dev/null +++ b/src/m_str.c @@ -0,0 +1,52 @@ +// Copyright © 2017 Project Golan, all rights reserved. +#include "m_str.h" +#include "m_types.h" + +#include + +#include +#include +#include + +// Extern Functions ----------------------------------------------------------| + +// +// M_StrFmt +// +char *M_StrFmt(char const *fmt, ...) +{ + [[__no_init]] + static char bufs[3][0x2800]; + static int idx; + + va_list va; + + if(++idx == M_countof(bufs)) idx = 0; + + va_start(va, fmt); + vsnprintf(bufs[idx], sizeof(bufs[idx]), fmt, va); + va_end(va); + + return bufs[idx]; +} + +// +// M_StrHash +// +mword M_StrHash(char const *s) +{ + mword h = 0; + for(; *s; s++) + h = h * 101 + *s; + return h; +} + +// +// M_StrCreate +// +__str M_StrCreate(char const *s) +{ + return DGE_String_Create(s, strlen(s)); +} + +// EOF diff --git a/src/m_str.h b/src/m_str.h new file mode 100644 index 0000000..e2ee497 --- /dev/null +++ b/src/m_str.h @@ -0,0 +1,16 @@ +// Copyright © 2017 Project Golan, all rights reserved. +#ifndef m_str_h +#define m_str_h + +#include "m_types.h" + +#define M_strbufcpy(a, b) strncpy((a), (b), M_countof(a)) + +// Extern Functions ----------------------------------------------------------| + +char *M_StrFmt(char const *fmt, ...); +mword M_StrHash(char const *s); +__str M_StrCreate(char const *s); +char *M_StrDup(char const *s); + +#endif diff --git a/src/m_token.c b/src/m_token.c new file mode 100644 index 0000000..ffaf7da --- /dev/null +++ b/src/m_token.c @@ -0,0 +1,148 @@ +// Copyright © 2017 Project Golan, all rights reserved. +#include "m_token.h" + +#include + +#define M_Tk_getPredStr(s, fn) \ + do { \ + int i; \ + for(i = (s); i < M_countof(tok->text)-1 && fn(ch); i++, ch = fgetc(fp)) \ + tok->text[i] = ch; \ + tok->text[i] = '\0'; \ + ungetc(ch, fp); \ + } while(0) + +#define M_Tk_isidenti(ch) (isalnum(ch) || (ch) == '_') +#define M_Tk_isnum(ch) (isalnum(ch) || (ch) == '_' || (ch) == '.') + +// Extern Functions ----------------------------------------------------------| + +// +// M_Tk_Parse +// +void M_Tk_Parse(FILE *fp, M_token *tok) +{ + if(!tok) return; + + tok->text[0] = '\0'; + + if(!fp || feof(fp)) { + tok->type = tok_eof; + return; + } + +begin:; + int ch; + switch((ch = fgetc(fp))) + { + case EOF: + case '\0': tok->type = tok_eof; return; + case '\r': if((ch = fgetc(fp)) != '\n') ungetc(ch, fp); + case '\n': tok->type = tok_lnend; return; + case ';': tok->type = tok_semico; return; + case ',': tok->type = tok_comma; return; + case '[': tok->type = tok_bracko; return; + case ']': tok->type = tok_brackc; return; + case '{': tok->type = tok_braceo; return; + case '}': tok->type = tok_bracec; return; + case '(': tok->type = tok_pareno; return; + case ')': tok->type = tok_parenc; return; + #define TokOp2(c, c2, t, t2) \ + case c: \ + if((ch = fgetc(fp)) == c2) tok->type = t2; \ + else {ungetc(ch, fp); tok->type = t;} \ + return + TokOp2('=', '=', tok_eq, tok_eq2); + TokOp2('?', '=', tok_tern, tok_terneq); + TokOp2('!', '=', tok_not, tok_neq); + TokOp2('~', '=', tok_bnot, tok_bneq); + TokOp2('*', '=', tok_mul, tok_muleq); + TokOp2('@', '@', tok_at, tok_at2); + #undef TokOp2 + #define TokOp3(c, t, t2, teq) \ + case c: \ + if((ch = fgetc(fp)) == c) tok->type = t2; \ + else if(ch == '=') tok->type = teq; \ + else {ungetc(ch, fp); tok->type = t;} \ + return + TokOp3('<', tok_lt, tok_lt2, tok_le); + TokOp3('>', tok_gt, tok_gt2, tok_ge); + TokOp3('|', tok_or, tok_or2, tok_oreq); + TokOp3('&', tok_and, tok_and2, tok_andeq); + TokOp3('+', tok_add, tok_add2, tok_addeq); + TokOp3('%', tok_mod, tok_mod2, tok_modeq); + TokOp3('^', tok_xor, tok_xor2, tok_xoreq); + TokOp3(':', tok_col, tok_col2, tok_coleq); + #undef TokOp3 + case '-': + if((ch = fgetc(fp)) == '-') tok->type = tok_sub2; + else if(ch == '=') tok->type = tok_subeq; + else if(ch == '>') tok->type = tok_rarrow; + else if(isdigit(ch)) {ungetc(ch, fp); ch = '-'; break;} + else {ungetc(ch, fp); tok->type = tok_sub;} + return; + case '/': + if((ch = fgetc(fp)) == '=') + tok->type = tok_diveq; + else if(ch == '/') + { + #define incmt(ch) ((ch) != '\n' && !feof(fp)) + ch = fgetc(fp); + M_Tk_getPredStr(0, incmt); + tok->type = tok_cmtlin; + #undef incmt + } + else + {ungetc(ch, fp); tok->type = tok_div;} + return; + case '.': + if((ch = fgetc(fp)) == '.') + { + if((ch = fgetc(fp)) == '.') + tok->type = tok_dot3; + else + {ungetc(ch, fp); tok->type = tok_dot2;} + } + else if(isdigit(ch)) + {ungetc(ch, fp); break;} + else + {ungetc(ch, fp); tok->type = tok_dot;} + return; + case '\'': tok->type = tok_charac; goto string; + case '"': tok->type = tok_string; goto string; + string: { + int i, beg; + for(i = 0, beg = ch; (ch = fgetc(fp)) != beg && !feof(fp); i++) + tok->text[i] = ch; + tok->text[i] = '\0'; + return; + } + } + + if(isblank(ch)) + { + while(isblank(ch = fgetc(fp))); + ungetc(ch, fp); + goto begin; + } + else if(isdigit(ch) || ch == '.' || ch == '-') + { + tok->text[0] = ch; + ch = fgetc(fp); + M_Tk_getPredStr(1, M_Tk_isnum); + tok->type = tok_number; + } + else if(M_Tk_isidenti(ch)) + { + M_Tk_getPredStr(0, M_Tk_isidenti); + tok->type = tok_identi; + } + else + { + tok->text[0] = ch; + tok->text[1] = '\0'; + tok->type = tok_chrseq; + } +} + +// EOF diff --git a/src/m_token.h b/src/m_token.h new file mode 100644 index 0000000..5b54ac0 --- /dev/null +++ b/src/m_token.h @@ -0,0 +1,100 @@ +// Copyright © 2017 Project Golan, all rights reserved. +#ifndef m_token_h +#define m_token_h + +#include "m_types.h" + +#include + +// Types ---------------------------------------------------------------------| + +typedef enum M_tokty +{ + tok_null, // No token + + // Text sequences + tok_chrseq, // Arbitrary character sequence + tok_identi, // Identifier + tok_number, // Number + tok_string, // String < " > < " > + tok_charac, // Character String < ' > < ' > + tok_cmtlin, // Line comment < // > < \n > + + // Single characters + tok_lnend, // \n + tok_semico, // ; + tok_comma, // , + tok_bracko, // [ + tok_brackc, // ] + tok_braceo, // { + tok_bracec, // } + tok_pareno, // ( + tok_parenc, // ) + + // Paired operators + tok_eq, // = + tok_eq2, // == + tok_tern, // ? + tok_terneq, // ?= + tok_div, // / + tok_diveq, // /= + tok_not, // ! + tok_neq, // != + tok_bnot, // ~ + tok_bneq, // ~= + tok_mul, // * + tok_muleq, // *= + tok_at, // @ + tok_at2, // @@ + + // Tupled operators + tok_lt, // < + tok_lt2, // << + tok_le, // <= + tok_gt, // > + tok_gt2, // >> + tok_ge, // >= + tok_or, // | + tok_or2, // || + tok_oreq, // |= + tok_and, // & + tok_and2, // && + tok_andeq, // &= + tok_add, // + + tok_add2, // ++ + tok_addeq, // += + tok_sub, // - + tok_sub2, // -- + tok_subeq, // -= + tok_mod, // % + tok_mod2, // %% + tok_modeq, // %= + tok_xor, // ^ + tok_xor2, // ^^ + tok_xoreq, // ^= + tok_col, // : + tok_col2, // :: + tok_coleq, // := + + // Misc + tok_dot, // . + tok_dot2, // .. + tok_dot3, // ... + tok_rarrow, // -> + tok_eof, // End of file + + tok_max +} M_tokty; + +typedef struct M_token +{ + M_tokty type; + int line; + char text[1024]; +} M_token; + +// Extern Functions ----------------------------------------------------------| + +void M_Tk_Parse(FILE *fp, M_token *tok); + +#endif diff --git a/src/m_types.h b/src/m_types.h new file mode 100644 index 0000000..a4123cb --- /dev/null +++ b/src/m_types.h @@ -0,0 +1,31 @@ +// Copyright © 2017 Project Golan, all rights reserved. +#ifndef m_types_h +#define m_types_h + +#include +#include +#include +#include +#undef fixed + +#define M_countof(a) (sizeof(a) / sizeof(*a)) + +// Types ---------------------------------------------------------------------| + +typedef short accum fixed; // Fixed +typedef long fract lfrac; // Long Fractional +typedef size_t msize; // Machine Size +typedef ptrdiff_t mpdif; // Machine Pointer Difference +typedef uint8_t mbyte; // Machine Byte +typedef uint16_t hword; // Half Word +typedef uint32_t mword; // Machine Word +typedef uint64_t dword; // Double Word +typedef uint96_t tword; // Triple Word +typedef int8_t chara; // Character +typedef int16_t int16; // Integer (16 bits) +typedef int32_t integ; // Integer (Machine) +typedef int64_t int64; // Integer (64 bits) +typedef int96_t int96; // Integer (96 bits) +typedef unsigned M_texid; // Texture ID + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..a644b41 --- /dev/null +++ b/src/main.c @@ -0,0 +1,74 @@ +// Copyright © 2017 Project Golan, all rights reserved. +#include "g_object.h" +#include "m_types.h" + +#include + +#include + +// Static Functions ----------------------------------------------------------| + +// +// G_Player_Think +// +DGE_Callback static void G_Player_Think(DGE_Entity ent) +{ + DGE_Object_RefAdd(ent.id); + + for(;;) + { + if(ent.health <= 0) + break; + + ent.vx = ent.vx + (fixed)DGE_GetInputAxis(0, DGE_Axis_X); + ent.vy = ent.vy - (fixed)DGE_GetInputAxis(0, DGE_Axis_Y); + + DGE_Task_Sleep(0, 1); + } + + DGE_Object_RefSub(ent.id); +} + +// +// G_Player_Create +// +static DGE_Entity G_Player_Create(fixed x, fixed y) +{ + DGE_Entity ent = {DGE_Entity_Create(0)}; + ent.x = x; + ent.y = y; + G_entty const *type; + if((type = G_ObjDef_GetType("Player"))) { + G_ObjDef_setupEntity(type, ent); + G_ObjDef_createTask (type, ent); + } + return ent; +} + +// Extern Functions ----------------------------------------------------------| + +// +// main +// +[[__extern("asm")]] DGE_Callback +void main(void) +{ + printf("\n=====================\n" + u8"オミ:影響の目 1.0\n" + u8"Copyright © 2017 Project Golan, all rights reserved.\n\n"); + + DGE_SetVirtualResolution(640, 480); + + printf("Loading object function table...\n"); + G_ObjDef_Init(); + G_ObjDef_loadFunc(G_Player_Think); + + printf("Loading object definitions...\n"); + G_ObjDef_Load("objdefs.dod"); + + printf("Ready.\n"); + + G_Player_Create(32, 32); +} + +// EOF