Added '...(idx,type)' to access varargs

This commit is contained in:
Wolfgang Bumiller 2013-01-12 14:53:48 +01:00
parent cd543aad5e
commit e149551744
2 changed files with 140 additions and 23 deletions

50
lexer.c
View file

@ -1244,31 +1244,37 @@ int lex_do(lex_file *lex)
default:
break;
}
}
if (ch == '.')
{
lex_tokench(lex, ch);
/* peak ahead once */
nextch = lex_getch(lex);
if (nextch != '.') {
lex_ungetch(lex, nextch);
lex_endtoken(lex);
return (lex->tok.ttype = ch);
}
/* peak ahead again */
nextch = lex_getch(lex);
if (nextch != '.') {
lex_ungetch(lex, nextch);
lex_ungetch(lex, '.');
lex_endtoken(lex);
return (lex->tok.ttype = ch);
}
/* fill the token to be "..." */
lex_tokench(lex, ch);
lex_tokench(lex, ch);
if (ch == '.')
{
lex_tokench(lex, ch);
/* peak ahead once */
nextch = lex_getch(lex);
if (nextch != '.') {
lex_ungetch(lex, nextch);
lex_endtoken(lex);
return (lex->tok.ttype = TOKEN_DOTS);
if (lex->flags.noops)
return (lex->tok.ttype = ch);
else
return (lex->tok.ttype = TOKEN_OPERATOR);
}
/* peak ahead again */
nextch = lex_getch(lex);
if (nextch != '.') {
lex_ungetch(lex, nextch);
lex_ungetch(lex, '.');
lex_endtoken(lex);
if (lex->flags.noops)
return (lex->tok.ttype = ch);
else
return (lex->tok.ttype = TOKEN_OPERATOR);
}
/* fill the token to be "..." */
lex_tokench(lex, ch);
lex_tokench(lex, ch);
lex_endtoken(lex);
return (lex->tok.ttype = TOKEN_DOTS);
}
if (ch == ',' || ch == '.') {

113
parser.c
View file

@ -105,7 +105,7 @@ typedef struct {
size_t max_param_count;
} parser_t;
static const ast_expression *intrinsic_debug_typestring = (ast_expression*)0x10;
static ast_expression * const intrinsic_debug_typestring = (ast_expression*)0x1;
static void parser_enterblock(parser_t *parser);
static bool parser_leaveblock(parser_t *parser);
@ -121,6 +121,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
static ast_expression* parse_expression(parser_t *parser, bool stopatcomma, bool with_labels);
static ast_value* parser_create_array_setter_proto(parser_t *parser, ast_value *array, const char *funcname);
static ast_value* parser_create_array_getter_proto(parser_t *parser, ast_value *array, const ast_expression *elemtype, const char *funcname);
static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef);
static void parseerror(parser_t *parser, const char *fmt, ...)
{
@ -1555,6 +1556,102 @@ static void parser_reclassify_token(parser_t *parser)
}
}
static ast_expression* parse_vararg_do(parser_t *parser)
{
ast_expression *idx, *out;
ast_value *typevar;
ast_value *funtype = parser->function->vtype;
lex_ctx ctx = parser_ctx(parser);
if (!parser_next(parser) || parser->tok != '(') {
parseerror(parser, "expected parameter index and type in parenthesis");
return NULL;
}
if (!parser_next(parser)) {
parseerror(parser, "error parsing parameter index");
return NULL;
}
idx = parse_expression_leave(parser, true, false, false);
if (!idx)
return NULL;
if (parser->tok != ',') {
ast_unref(idx);
parseerror(parser, "expected comma after parameter index");
return NULL;
}
if (!parser_next(parser) || (parser->tok != TOKEN_IDENT && parser->tok != TOKEN_TYPENAME)) {
ast_unref(idx);
parseerror(parser, "expected typename for vararg");
return NULL;
}
typevar = parse_typename(parser, NULL, NULL);
if (!typevar) {
ast_unref(idx);
return NULL;
}
if (parser->tok != ')') {
ast_unref(idx);
ast_delete(typevar);
parseerror(parser, "expected closing paren");
return NULL;
}
#if 0
if (!parser_next(parser)) {
ast_unref(idx);
ast_delete(typevar);
parseerror(parser, "parse error after vararg");
return NULL;
}
#endif
if (!parser->function->varargs) {
ast_unref(idx);
ast_delete(typevar);
parseerror(parser, "function has no variable argument list");
return NULL;
}
if (funtype->expression.varparam &&
!ast_compare_type((ast_expression*)typevar, (ast_expression*)funtype->expression.varparam))
{
char ty1[1024];
char ty2[1024];
ast_type_to_string((ast_expression*)typevar, ty1, sizeof(ty1));
ast_type_to_string((ast_expression*)funtype->expression.varparam, ty2, sizeof(ty2));
compile_error(ast_ctx(typevar),
"function was declared to take varargs of type `%s`, requested type is: %s",
ty2, ty1);
}
out = (ast_expression*)ast_array_index_new(ctx, (ast_expression*)(parser->function->varargs), idx);
ast_type_adopt(out, typevar);
ast_delete(typevar);
return out;
}
static ast_expression* parse_vararg(parser_t *parser)
{
bool old_noops = parser->lex->flags.noops;
enum parser_pot *old_pot = parser->pot;
ast_expression *out;
parser->pot = NULL;
parser->lex->flags.noops = true;
out = parse_vararg_do(parser);
parser->pot = old_pot;
parser->lex->flags.noops = old_noops;
return out;
}
static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue, bool with_labels)
{
ast_expression *expr = NULL;
@ -1613,6 +1710,20 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
goto onerr;
}
}
else if (parser->tok == TOKEN_DOTS)
{
ast_expression *va;
if (wantop) {
parseerror(parser, "expected operator or end of statement");
goto onerr;
}
wantop = true;
va = parse_vararg(parser);
if (!va)
goto onerr;
vec_push(sy.out, syexp(parser_ctx(parser), va));
DEBUGSHUNTDO(con_out("push `...`\n"));
}
else if (parser->tok == TOKEN_IDENT)
{
const char *ctoken = parser_tokval(parser);