From f387fea2b957ba6beaa20c6db2c57d05b9bdae3e Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Thu, 17 Oct 2013 07:40:51 -0400 Subject: [PATCH] Initial idea at implementing type-generic length operator like C's sizeof. The following semantics are present: len(array) gives you a constant-evaluated value of the number of elements in that array. len(string) gives you the strlen of a string. Other semantics to come. Since this is an operator you can eliminate the parens, thus "len array" works. --- fold.c | 10 ++++++++++ lexer.c | 17 +++++++++++++++++ lexer.h | 1 + parser.c | 12 ++++++++++++ 4 files changed, 40 insertions(+) diff --git a/fold.c b/fold.c index 4664487..18fa496 100644 --- a/fold.c +++ b/fold.c @@ -41,6 +41,7 @@ #define isfloat(X) (((ast_expression*)(X))->vtype == TYPE_FLOAT) #define isvector(X) (((ast_expression*)(X))->vtype == TYPE_VECTOR) #define isstring(X) (((ast_expression*)(X))->vtype == TYPE_STRING) +#define isarray(X) (((ast_expression*)(X))->vtype == TYPE_ARRAY) #define isfloats(X,Y) (isfloat (X) && isfloat (Y)) /* @@ -632,6 +633,14 @@ static GMQCC_INLINE ast_expression *fold_op_cross(fold_t *fold, ast_value *a, as return NULL; } +static GMQCC_INLINE ast_expression *fold_op_length(fold_t *fold, ast_value *a) { + if (fold_can_1(a) && isstring(a)) + return fold_constgen_float(fold, strlen(fold_immvalue_string(a))); + if (isarray(a)) + return fold_constgen_float(fold, vec_size(a->initlist)); + return NULL; +} + ast_expression *fold_op(fold_t *fold, const oper_info *info, ast_expression **opexprs) { ast_value *a = (ast_value*)opexprs[0]; ast_value *b = (ast_value*)opexprs[1]; @@ -690,6 +699,7 @@ ast_expression *fold_op(fold_t *fold, const oper_info *info, ast_expression **op fold_op_case(2, ('=', '='), cmp, (fold, a, b, false)); fold_op_case(2, ('~', 'P'), bnot, (fold, a)); fold_op_case(2, ('>', '<'), cross, (fold, a, b)); + fold_op_case(3, ('l','e','n'), length, (fold, a)); } #undef fold_op_case compile_error(fold_ctx(fold), "internal error: attempted to constant-fold for unsupported operator"); diff --git a/lexer.c b/lexer.c index b6d5ceb..5030e78 100644 --- a/lexer.c +++ b/lexer.c @@ -1396,6 +1396,23 @@ int lex_do(lex_file *lex) return (lex->tok.ttype = TOKEN_OPERATOR); } + /* len operator */ + if (ch == 'l') { + if ((nextch = lex_getch(lex)) == 'e') { + if ((nextch = lex_getch(lex)) == 'n') { + lex_tokench(lex, 'l'); + lex_tokench(lex, 'e'); + lex_tokench(lex, 'n'); + lex_endtoken(lex); + return (lex->tok.ttype = TOKEN_OPERATOR); + } else { + lex_ungetch(lex, nextch); + } + } else { + lex_ungetch(lex, nextch); + } + } + if (isident_start(ch)) { const char *v; diff --git a/lexer.h b/lexer.h index 44f6491..28e05ec 100644 --- a/lexer.h +++ b/lexer.h @@ -175,6 +175,7 @@ typedef struct { static const oper_info c_operators[] = { { "(", 0, opid1('('), ASSOC_LEFT, 99, OP_PREFIX, false}, /* paren expression - non function call */ + { "len", 1, opid3('l','e','n'), ASSOC_RIGHT, 98, OP_PREFIX, true}, /* len operator */ { "++", 1, opid3('S','+','+'), ASSOC_LEFT, 17, OP_SUFFIX, false}, { "--", 1, opid3('S','-','-'), ASSOC_LEFT, 17, OP_SUFFIX, false}, diff --git a/parser.c b/parser.c index 82ce53b..acad4be 100644 --- a/parser.c +++ b/parser.c @@ -1109,6 +1109,18 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) out = (ast_expression*)asbinstore; break; + case opid3('l', 'e', 'n'): + if (exprs[0]->vtype != TYPE_ARRAY && exprs[0]->vtype != TYPE_STRING) { + ast_type_to_string(exprs[0], ty1, sizeof(ty1)); + compile_error(ast_ctx(exprs[0]), "invalid type for length operator: %s", ty1); + return false; + } + if (!(out = fold_op(parser->fold, op, exprs))) { + compile_error(ast_ctx(exprs[0]), "expected constant expression as operand to length operator"); + return false; + } + break; + case opid2('~', 'P'): if (exprs[0]->vtype != TYPE_FLOAT && exprs[0]->vtype != TYPE_VECTOR) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); -- 2.39.2