mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2025-02-17 09:02:25 +00:00
while, for
This commit is contained in:
parent
1c4a11f6fb
commit
69d9afbc69
2 changed files with 174 additions and 14 deletions
187
parser.c
187
parser.c
|
@ -41,6 +41,13 @@ MEM_VEC_FUNCTIONS(parser_t, ast_value*, imm_vector)
|
|||
MEM_VEC_FUNCTIONS(parser_t, varentry_t, locals)
|
||||
MEM_VEC_FUNCTIONS(parser_t, ast_function*, functions)
|
||||
|
||||
static void parser_pop_local(parser_t *parser);
|
||||
static bool parser_variable(parser_t *parser, ast_block *localblock);
|
||||
static ast_block* parser_parse_block(parser_t *parser);
|
||||
static ast_expression* parser_parse_statement_or_block(parser_t *parser);
|
||||
static ast_expression* parser_expression_leave(parser_t *parser);
|
||||
static ast_expression* parser_expression(parser_t *parser);
|
||||
|
||||
void parseerror(parser_t *parser, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
@ -59,6 +66,36 @@ void parseerror(parser_t *parser, const char *fmt, ...)
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
/* returns true if it counts as an error */
|
||||
bool parsewarning(parser_t *parser, int warntype, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
#if 0
|
||||
if (OPTS_WARN(WARN_ERROR))
|
||||
parser->errors++;
|
||||
#endif
|
||||
|
||||
if (!OPTS_WARN(warntype))
|
||||
return false;
|
||||
|
||||
if (parser)
|
||||
printf("warning %s:%lu: ", parser->lex->tok->ctx.file, (unsigned long)parser->lex->tok->ctx.line);
|
||||
else
|
||||
printf("warning: ");
|
||||
|
||||
va_start(ap, fmt);
|
||||
vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
printf("\n");
|
||||
#if 0
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool parser_next(parser_t *parser)
|
||||
{
|
||||
/* lex_do kills the previous token */
|
||||
|
@ -705,7 +742,7 @@ static bool parser_close_paren(parser_t *parser, shunt *sy, bool functions_only)
|
|||
return true;
|
||||
}
|
||||
|
||||
static ast_expression* parser_expression(parser_t *parser)
|
||||
static ast_expression* parser_expression_leave(parser_t *parser)
|
||||
{
|
||||
ast_expression *expr = NULL;
|
||||
shunt sy;
|
||||
|
@ -924,10 +961,6 @@ static ast_expression* parser_expression(parser_t *parser)
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (parens >= 0 && !parser_next(parser)) {
|
||||
parseerror(parser, "Unexpected end of file");
|
||||
goto onerr;
|
||||
}
|
||||
|
||||
while (sy.ops_count) {
|
||||
if (!parser_sy_pop(parser, &sy))
|
||||
|
@ -952,9 +985,17 @@ onerr:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static bool parser_variable(parser_t *parser, ast_block *localblock);
|
||||
static ast_block* parser_parse_block(parser_t *parser);
|
||||
static ast_expression* parser_parse_statement_or_block(parser_t *parser);
|
||||
static ast_expression* parser_expression(parser_t *parser)
|
||||
{
|
||||
ast_expression *e = parser_expression_leave(parser);
|
||||
if (!e)
|
||||
return NULL;
|
||||
if (!parser_next(parser)) {
|
||||
ast_delete(e);
|
||||
return NULL;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static bool parser_parse_if(parser_t *parser, ast_block *block, ast_expression **out)
|
||||
{
|
||||
|
@ -974,7 +1015,7 @@ static bool parser_parse_if(parser_t *parser, ast_block *block, ast_expression *
|
|||
return false;
|
||||
}
|
||||
/* parse the condition */
|
||||
cond = parser_expression(parser);
|
||||
cond = parser_expression_leave(parser);
|
||||
if (!cond)
|
||||
return false;
|
||||
/* closing paren */
|
||||
|
@ -1025,27 +1066,27 @@ static bool parser_parse_while(parser_t *parser, ast_block *block, ast_expressio
|
|||
|
||||
/* skip the 'while' and check for opening paren */
|
||||
if (!parser_next(parser) || parser->tok != '(') {
|
||||
parseerror(parser, "expected 'if' condition in parenthesis");
|
||||
parseerror(parser, "expected 'while' condition in parenthesis");
|
||||
return false;
|
||||
}
|
||||
/* parse into the expression */
|
||||
if (!parser_next(parser)) {
|
||||
parseerror(parser, "expected 'if' condition after opening paren");
|
||||
parseerror(parser, "expected 'while' condition after opening paren");
|
||||
return false;
|
||||
}
|
||||
/* parse the condition */
|
||||
cond = parser_expression(parser);
|
||||
cond = parser_expression_leave(parser);
|
||||
if (!cond)
|
||||
return false;
|
||||
/* closing paren */
|
||||
if (parser->tok != ')') {
|
||||
parseerror(parser, "expected closing paren after 'if' condition");
|
||||
parseerror(parser, "expected closing paren after 'while' condition");
|
||||
ast_delete(cond);
|
||||
return false;
|
||||
}
|
||||
/* parse into the 'then' branch */
|
||||
if (!parser_next(parser)) {
|
||||
parseerror(parser, "expected statement for on-true branch of 'if'");
|
||||
parseerror(parser, "expected while-loop body");
|
||||
ast_delete(cond);
|
||||
return false;
|
||||
}
|
||||
|
@ -1060,6 +1101,120 @@ static bool parser_parse_while(parser_t *parser, ast_block *block, ast_expressio
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool parser_parse_for(parser_t *parser, ast_block *block, ast_expression **out)
|
||||
{
|
||||
ast_loop *aloop;
|
||||
ast_expression *initexpr, *cond, *increment, *ontrue;
|
||||
size_t oldblocklocal;
|
||||
|
||||
lex_ctx ctx = parser_ctx(parser);
|
||||
|
||||
oldblocklocal = parser->blocklocal;
|
||||
parser->blocklocal = parser->locals_count;
|
||||
|
||||
initexpr = NULL;
|
||||
cond = NULL;
|
||||
increment = NULL;
|
||||
ontrue = NULL;
|
||||
|
||||
/* skip the 'while' and check for opening paren */
|
||||
if (!parser_next(parser) || parser->tok != '(') {
|
||||
parseerror(parser, "expected 'for' expressions in parenthesis");
|
||||
goto onerr;
|
||||
}
|
||||
/* parse into the expression */
|
||||
if (!parser_next(parser)) {
|
||||
parseerror(parser, "expected 'for' initializer after opening paren");
|
||||
goto onerr;
|
||||
}
|
||||
|
||||
if (parser->tok == TOKEN_TYPENAME) {
|
||||
if (opts_standard != COMPILER_GMQCC) {
|
||||
if (parsewarning(parser, WARN_EXTENSIONS,
|
||||
"current standard does not allow variable declarations in for-loop initializers"))
|
||||
goto onerr;
|
||||
}
|
||||
|
||||
parseerror(parser, "TODO: assignment of new variables to be non-const");
|
||||
goto onerr;
|
||||
if (!parser_variable(parser, block))
|
||||
goto onerr;
|
||||
}
|
||||
else if (parser->tok != ';')
|
||||
{
|
||||
initexpr = parser_expression_leave(parser);
|
||||
if (!initexpr)
|
||||
goto onerr;
|
||||
}
|
||||
|
||||
/* move on to condition */
|
||||
if (parser->tok != ';') {
|
||||
parseerror(parser, "expected semicolon after for-loop initializer");
|
||||
goto onerr;
|
||||
}
|
||||
if (!parser_next(parser)) {
|
||||
parseerror(parser, "expected for-loop condition");
|
||||
goto onerr;
|
||||
}
|
||||
|
||||
/* parse the condition */
|
||||
if (parser->tok != ';') {
|
||||
printf("going cond!\n");
|
||||
cond = parser_expression_leave(parser);
|
||||
if (!cond)
|
||||
goto onerr;
|
||||
printf("going cond!\n");
|
||||
}
|
||||
|
||||
/* move on to incrementor */
|
||||
if (parser->tok != ';') {
|
||||
parseerror(parser, "expected semicolon after for-loop initializer");
|
||||
goto onerr;
|
||||
}
|
||||
if (!parser_next(parser)) {
|
||||
parseerror(parser, "expected for-loop condition");
|
||||
goto onerr;
|
||||
}
|
||||
|
||||
/* parse the incrementor */
|
||||
if (parser->tok != ')') {
|
||||
increment = parser_expression_leave(parser);
|
||||
if (!increment)
|
||||
goto onerr;
|
||||
}
|
||||
|
||||
/* closing paren */
|
||||
if (parser->tok != ')') {
|
||||
parseerror(parser, "expected closing paren after 'for-loop' incrementor");
|
||||
goto onerr;
|
||||
}
|
||||
/* parse into the 'then' branch */
|
||||
if (!parser_next(parser)) {
|
||||
parseerror(parser, "expected for-loop body");
|
||||
goto onerr;
|
||||
}
|
||||
ontrue = parser_parse_statement_or_block(parser);
|
||||
if (!ontrue) {
|
||||
goto onerr;
|
||||
}
|
||||
|
||||
aloop = ast_loop_new(ctx, initexpr, cond, NULL, increment, ontrue);
|
||||
*out = (ast_expression*)aloop;
|
||||
|
||||
while (parser->locals_count > parser->blocklocal)
|
||||
parser_pop_local(parser);
|
||||
parser->blocklocal = oldblocklocal;
|
||||
return true;
|
||||
onerr:
|
||||
if (initexpr) ast_delete(initexpr);
|
||||
if (cond) ast_delete(cond);
|
||||
if (increment) ast_delete(increment);
|
||||
while (parser->locals_count > parser->blocklocal)
|
||||
parser_pop_local(parser);
|
||||
parser->blocklocal = oldblocklocal;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool parser_parse_statement(parser_t *parser, ast_block *block, ast_expression **out)
|
||||
{
|
||||
if (parser->tok == TOKEN_TYPENAME)
|
||||
|
@ -1119,6 +1274,10 @@ static bool parser_parse_statement(parser_t *parser, ast_block *block, ast_expre
|
|||
{
|
||||
return parser_parse_while(parser, block, out);
|
||||
}
|
||||
else if (!strcmp(parser_tokval(parser), "for"))
|
||||
{
|
||||
return parser_parse_for(parser, block, out);
|
||||
}
|
||||
parseerror(parser, "Unexpected keyword");
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -4,3 +4,4 @@
|
|||
|
||||
GMQCC_DEFINE_FLAG(UNUSED_VARIABLE)
|
||||
GMQCC_DEFINE_FLAG(UNKNOWN_CONTROL_SEQUENCE)
|
||||
GMQCC_DEFINE_FLAG(EXTENSIONS)
|
||||
|
|
Loading…
Reference in a new issue