From e00c8da849f4804bca8e11a167ae3d2c58233693 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Thu, 16 Aug 2012 20:47:31 +0200 Subject: [PATCH] Added support for some modelgen/spritegen commands --- data/parsing.qc | 4 ++ lexer.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++- lexer.h | 8 +++ parser.c | 7 +++ 4 files changed, 161 insertions(+), 2 deletions(-) diff --git a/data/parsing.qc b/data/parsing.qc index 42ee938..5c61f8c 100644 --- a/data/parsing.qc +++ b/data/parsing.qc @@ -11,6 +11,9 @@ void(entity) kill = #4; .float mema; .float memb; +$framevalue 37 +$frame stand1 stand2 stand3 + void() main = { entity pawn; vector vec; @@ -59,4 +62,5 @@ void() main = { print3("memb = ", ftos(pawn.memb), "\n"); pawn.memb += -1; print3("memb = ", ftos(pawn.memb), "\n"); + print3("Frame stand3 is ", ftos(stand3), " wooh\n"); }; diff --git a/lexer.c b/lexer.c index 94e0cbb..c35a88c 100644 --- a/lexer.c +++ b/lexer.c @@ -7,6 +7,7 @@ #include "lexer.h" MEM_VEC_FUNCTIONS(token, char, value) +MEM_VEC_FUNCTIONS(lex_file, frame_macro, frames) void lexerror(lex_file *lex, const char *fmt, ...) { @@ -342,6 +343,58 @@ static bool GMQCC_WARN lex_finish_ident(lex_file *lex) return true; } +/* read one ident for the frame list */ +static int lex_parse_frame(lex_file *lex) +{ + int ch; + + if (lex->tok) + token_delete(lex->tok); + lex->tok = token_new(); + + ch = lex_getch(lex); + while (ch != EOF && ch != '\n' && isspace(ch)) + ch = lex_getch(lex); + + if (ch == '\n') + return 1; + + if (!isident_start(ch)) { + lexerror(lex, "invalid framename, must start with one of a-z or _, got %c", ch); + return -1; + } + + if (!lex_tokench(lex, ch)) + return -1; + if (!lex_finish_ident(lex)) + return -1; + if (!lex_endtoken(lex)) + return -1; + return 0; +} + +/* read a list of $frames */ +static bool lex_finish_frames(lex_file *lex) +{ + do { + int rc; + frame_macro m; + + rc = lex_parse_frame(lex); + if (rc > 0) /* end of line */ + return true; + if (rc < 0) /* error */ + return false; + + m.value = lex->framevalue++; + m.name = util_strdup(lex->tok->value); + if (!m.name || !lex_file_frames_add(lex, m)) { + lexerror(lex, "out of memory"); + return false; + } + } while (true); +} + static int GMQCC_WARN lex_finish_string(lex_file *lex, int quote) { int ch = 0; @@ -486,6 +539,87 @@ int lex_do(lex_file *lex) if (ch == EOF) return (lex->tok->ttype = TOKEN_EOF); + /* modelgen / spiritgen commands */ + if (ch == '$') { + const char *v; + ch = lex_getch(lex); + if (!isident_start(ch)) { + lexerror(lex, "hanging '$' modelgen/spritegen command line"); + return lex_do(lex); + } + if (!lex_tokench(lex, ch)) + return (lex->tok->ttype = TOKEN_FATAL); + if (!lex_finish_ident(lex)) + return (lex->tok->ttype = TOKEN_ERROR); + if (!lex_endtoken(lex)) + return (lex->tok->ttype = TOKEN_FATAL); + /* skip the known commands */ + v = lex->tok->value; + + if (!strcmp(v, "frame") || !strcmp(v, "framesave")) + { + /* frame/framesave command works like an enum + * similar to fteqcc we handle this in the lexer. + * The reason for this is that it is sensitive to newlines, + * which the parser is unaware of + */ + if (!lex_finish_frames(lex)) + return (lex->tok->ttype = TOKEN_ERROR); + return lex_do(lex); + } + + if (!strcmp(v, "framevalue")) + { + ch = lex_getch(lex); + while (ch != EOF && isspace(ch) && ch != '\n') + ch = lex_getch(lex); + + if (!isdigit(ch)) { + lexerror(lex, "$framevalue requires an integer parameter"); + return lex_do(lex); + } + + token_delete(lex->tok); + lex->tok = token_new(); + lex->tok->ttype = lex_finish_digit(lex, ch); + if (!lex_endtoken(lex)) + return (lex->tok->ttype = TOKEN_FATAL); + if (lex->tok->ttype != TOKEN_INTCONST) { + lexerror(lex, "$framevalue requires an integer parameter"); + return lex_do(lex); + } + lex->framevalue = lex->tok->constval.i; + return lex_do(lex); + } + + if (!strcmp(v, "flush")) + { + size_t frame; + for (frame = 0; frame < lex->frames_count; ++frame) + mem_d(lex->frames[frame].name); + MEM_VECTOR_CLEAR(lex, frames); + /* skip line (fteqcc does it too) */ + ch = lex_getch(lex); + while (ch != EOF && ch != '\n') + ch = lex_getch(lex); + return lex_do(lex); + } + + if (!strcmp(v, "cd") || + !strcmp(v, "origin") || + !strcmp(v, "base") || + !strcmp(v, "flags") || + !strcmp(v, "scale") || + !strcmp(v, "skin")) + { + /* skip line */ + ch = lex_getch(lex); + while (ch != EOF && ch != '\n') + ch = lex_getch(lex); + return lex_do(lex); + } + } + /* single-character tokens */ switch (ch) { @@ -497,8 +631,6 @@ int lex_do(lex_file *lex) case '[': case ']': - case '$': - case '#': if (!lex_tokench(lex, ch) || !lex_endtoken(lex)) @@ -606,6 +738,7 @@ int lex_do(lex_file *lex) if (isident_start(ch)) { const char *v; + size_t frame; if (!lex_tokench(lex, ch)) return (lex->tok->ttype = TOKEN_FATAL); if (!lex_finish_ident(lex)) { @@ -645,6 +778,13 @@ int lex_do(lex_file *lex) !strcmp(v, "const")) lex->tok->ttype = TOKEN_KEYWORD; + for (frame = 0; frame < lex->frames_count; ++frame) { + if (!strcmp(v, lex->frames[frame].name)) { + lex->tok->constval.i = lex->frames[frame].value; + return (lex->tok->ttype = TOKEN_INTCONST); + } + } + return lex->tok->ttype; } diff --git a/lexer.h b/lexer.h index c224c87..261fdf9 100644 --- a/lexer.h +++ b/lexer.h @@ -81,6 +81,11 @@ _all_tokennames_added_[ (sizeof(_tokennames)/sizeof(_tokennames[0]))) ? 1 : -1]; +typedef struct { + char *name; + int value; +} frame_macro; + typedef struct { FILE *file; char *name; @@ -95,6 +100,9 @@ typedef struct { struct { bool noops; } flags; + + int framevalue; + MEM_VECTOR_MAKE(frame_macro, frames); } lex_file; MEM_VECTOR_PROTO(lex_file, char, token); diff --git a/parser.c b/parser.c index 4105ce7..91c43f4 100644 --- a/parser.c +++ b/parser.c @@ -2160,6 +2160,13 @@ nextfield: return true; } + else if (parser->tok == '$') + { + if (!parser_next(parser)) { + parseerror(parser, "parse error"); + return false; + } + } else { parseerror(parser, "unexpected token: %s", parser->lex->tok->value); -- 2.39.2