Added support for some modelgen/spritegen commands

This commit is contained in:
Wolfgang (Blub) Bumiller 2012-08-16 20:47:31 +02:00
parent 91ee7658a6
commit e00c8da849
4 changed files with 161 additions and 2 deletions

View file

@ -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");
};

144
lexer.c
View file

@ -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;
}

View file

@ -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);

View file

@ -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);