Tue, 21 Apr 2015 12:13:41 +0200
minor grammar fix (alias name is now identifier and not string) + completed debugger (so far) + separated field list parser (currently unable to parse alias names) + new structure for fields
libidav/davqlparser.c | file | annotate | diff | comparison | revisions | |
libidav/davqlparser.h | file | annotate | diff | comparison | revisions |
--- a/libidav/davqlparser.c Fri Apr 17 16:26:53 2015 +0200 +++ b/libidav/davqlparser.c Tue Apr 21 12:13:41 2015 +0200 @@ -49,6 +49,7 @@ static const char* _map_exprtype(davqlexprtype_t type) { switch(type) { + case DAVQL_UNDEFINED_TYP: return "undefined"; case DAVQL_NUMBER: return "NUMBER"; case DAVQL_STRING: return "STRING"; case DAVQL_TIMESTAMP: return "TIMESTAMP"; @@ -92,13 +93,12 @@ // Basic information size_t fieldcount = ucx_list_size(stmt->fields); int specialfield = 0; - UCX_FOREACH(elm, stmt->fields) { - DavQLExpression* expr = (DavQLExpression*)elm->data; - if (expr->type == DAVQL_IDENTIFIER && expr->srctext.length == 1) { - if (expr->srctext.ptr[0] == '*') { - specialfield = 1; - } else if (expr->srctext.ptr[0] == '-') { - specialfield = 2; + if (stmt->fields) { + DavQLField* firstfield = (DavQLField*)stmt->fields->data; + if (firstfield->expr->type == DAVQL_IDENTIFIER) { + switch (firstfield->expr->srctext.ptr[0]) { + case '*': specialfield = 1; break; + case '-': specialfield = 2; break; } } } @@ -113,11 +113,6 @@ _map_specialfield(specialfield), sfmtarg(stmt->path), stmt->where ? "yes" : "no"); - if (stmt->type == DAVQL_SET) { - printf("Value list size matches: %s", - ucx_list_size(stmt->fields) == ucx_list_size(stmt->setvalues) - ? "yes" : "no"); - } // WITH attributes if (stmt->depth == DAV_DEPTH_INFINITY) { @@ -161,29 +156,41 @@ if (dav_debug_ql_expr_selected(expr)) { sstr_t empty = ST("(empty)"); printf( - "Text: %.*s\nType: %s\nOperator: %s\n" - "Left hand: %.*s\nRight hand: %.*s\n", + "Text: %.*s\nType: %s\nOperator: %s\n", sfmtarg(expr->srctext), _map_exprtype(expr->type), - _map_operator(expr->op), - sfmtarg(expr->left?expr->left->srctext:empty), - sfmtarg(expr->right?expr->right->srctext:empty)); + _map_operator(expr->op)); + if (expr->left || expr->right) { + printf("Left hand: %.*s\nRight hand: %.*s\n", + sfmtarg(expr->left?expr->left->srctext:empty), + sfmtarg(expr->right?expr->right->srctext:empty)); + } } } #define DQLD_CMD_Q 0 #define DQLD_CMD_PS 1 #define DQLD_CMD_PE 2 -#define DQLD_CMD_P 10 +#define DQLD_CMD_F 10 +#define DQLD_CMD_W 11 +#define DQLD_CMD_O 12 #define DQLD_CMD_L 21 #define DQLD_CMD_R 22 +#define DQLD_CMD_N 23 +#define DQLD_CMD_P 24 #define DQLD_CMD_H 100 static int dav_debug_ql_command() { printf("> "); - char buffer[16]; - fgets(buffer, 16, stdin); + char buffer[8]; + fgets(buffer, 8, stdin); + // discard remaining chars + if (!strchr(buffer, '\n')) { + int chr; + while ((chr = fgetc(stdin) != '\n') && chr != EOF); + } + if (!strcmp(buffer, "q\n")) { return DQLD_CMD_Q; } else if (!strcmp(buffer, "ps\n")) { @@ -196,6 +203,16 @@ return DQLD_CMD_R; } else if (!strcmp(buffer, "h\n")) { return DQLD_CMD_H; + } else if (!strcmp(buffer, "f\n")) { + return DQLD_CMD_F; + } else if (!strcmp(buffer, "w\n")) { + return DQLD_CMD_W; + } else if (!strcmp(buffer, "o\n")) { + return DQLD_CMD_O; + } else if (!strcmp(buffer, "n\n")) { + return DQLD_CMD_N; + } else if (!strcmp(buffer, "p\n")) { + return DQLD_CMD_P; } else { return -1; } @@ -215,6 +232,8 @@ } DavQLExpression *examineexpr = NULL; + UcxList *examineelem = NULL; + int examineclause = 0; while(1) { int cmd = dav_debug_ql_command(); @@ -222,6 +241,52 @@ case DQLD_CMD_Q: return; case DQLD_CMD_PS: dav_debug_ql_stmt_print(stmt); break; case DQLD_CMD_PE: dav_debug_ql_expr_print(examineexpr); break; + case DQLD_CMD_F: + if (examineclause != DQLD_CMD_F) { + examineclause = DQLD_CMD_F; + examineelem = stmt->fields; + examineexpr = stmt->fields ? + ((DavQLField*)stmt->fields->data)->expr : NULL; + dav_debug_ql_expr_print(examineexpr); + } + break; + case DQLD_CMD_W: + examineclause = 0; examineelem = NULL; + examineexpr = stmt->where; + dav_debug_ql_expr_print(examineexpr); + break; + case DQLD_CMD_O: + if (examineclause != DQLD_CMD_O) { + examineclause = DQLD_CMD_O; + examineelem = stmt->orderby; + examineexpr = stmt->orderby ? + ((DavQLOrderCriterion*)stmt->orderby->data)->column : NULL; + dav_debug_ql_expr_print(examineexpr); + } + break; + case DQLD_CMD_N: + case DQLD_CMD_P: + if (examineelem) { + UcxList *newelem = (cmd == DQLD_CMD_N ? + examineelem->next : examineelem->prev); + if (newelem) { + examineelem = newelem; + if (examineclause == DQLD_CMD_O) { + examineexpr = ((DavQLOrderCriterion*) + examineelem->data)->column; + } else if (examineclause == DQLD_CMD_F) { + examineexpr = ((DavQLField*)examineelem->data)->expr; + } else { + printf("Examining unknown clause type."); + } + dav_debug_ql_expr_print(examineexpr); + } else { + printf("Reached end of list.\n"); + } + } else { + printf("Currently not examining an expression list.\n"); + } + break; case DQLD_CMD_L: if (dav_debug_ql_expr_selected(examineexpr)) { if (examineexpr->left) { @@ -246,6 +311,13 @@ printf( "\nCommands:\n" "ps: print statement information\n" + "o: examine order by clause\n" + "f: examine field list\n" + "w: examine where clause\n" + "n: examine next expression " + "(in order by clause or field list)\n" + "p: examine previous expression " + "(in order by clause or field list)\n" "q: quit\n\n" "\nExpression examination:\n" "pe: print expression information\n" @@ -433,8 +505,10 @@ // process tokens for (size_t i = 0 ; i < n ; i++) { + sstr_t tokendata = *token_sstr(token); // TODO: make it so + printf("Processing %.*s...\n", sfmtarg(tokendata)); // go to next token (if this is not the last token) if (i < n-1) { @@ -468,6 +542,66 @@ #define _step_ORDER_BY_ 50 // ORDER BY clause #define _step_end_ 500 // expect end +struct fieldlist_parser_state { + UcxList *expr_firsttoken; + size_t expr_len; + /* + * 0: begin of field list - may encounter "*" or "-" special fields + * 1: collect expression token + * switch to step 2 on keyword "as" + * expect "," only if expr_len is 1 (add expr to list and continue) + * 2: expect one token (identifier) and a "," - continue with step 1 + */ + int step; +}; + +static int dav_parse_fieldlist(DavQLStatement *stmt, UcxList *token, + struct fieldlist_parser_state *state) { + sstr_t tokendata = *token_sstr(token); + + switch (state->step) { + case 0: + // did not encounter special field, fall through to step 1 + case 1: + break; + } + + _Bool fromkeyword = !sstrcasecmp(tokendata, S("from")); + if (fromkeyword || !sstrcmp(tokendata, S(","))) { + if (state->expr_firsttoken) { + DavQLField *field = malloc(sizeof(DavQLField)); + field->expr = dav_parse_expression( + stmt, state->expr_firsttoken, state->expr_len); + field->name = field->expr->srctext; + stmt->fields = ucx_list_append(stmt->fields, field); + state->expr_firsttoken = NULL; + state->expr_len = 0; + + if (fromkeyword) { + return _step_FROM_; + } + } else { + dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN, + _unexpected_token, stmt, token); + } + } else { + // collect tokens for field expression + if (state->expr_firsttoken) { + state->expr_len++; + } else { + state->expr_firsttoken = token; + state->expr_len = 1; + } + } + + return _step_fieldlist_; +} + +static void dav_free_field(DavQLField *field) { + dav_free_expression(field->expr); + free(field); +} + static int dav_parse_from(DavQLStatement *stmt, UcxList *token) { sstr_t tokendata = *token_sstr(token); @@ -693,16 +827,11 @@ memset(&state_with, 0, sizeof(struct with_parser_state)); struct orderby_parser_state state_orderby; memset(&state_orderby, 0, sizeof(struct orderby_parser_state)); - - // Variables for token sublists for expressions - // TODO: this is deprecated and won't work with function calls - UcxList *exprstart = NULL; - size_t exprlen = 0; + struct fieldlist_parser_state state_fieldlist; + memset(&state_fieldlist, 0, sizeof(struct fieldlist_parser_state)); // Process tokens UCX_FOREACH(token, tokens) { - sstr_t tokendata = *token_sstr(token); - switch (step) { // too much input data case _step_end_: @@ -711,30 +840,7 @@ break; // field list case _step_fieldlist_: { - _Bool fromkeyword = !sstrcasecmp(tokendata, S("from")); - if (fromkeyword || !sstrcmp(tokendata, S(","))) { - if (exprstart) { - stmt->fields = ucx_list_append(stmt->fields, - dav_parse_expression(stmt, exprstart, exprlen)); - exprstart = NULL; - exprlen = 0; - - if (fromkeyword) { - step = _step_FROM_; - } - } else { - dav_error_in_context(DAVQL_ERROR_UNEXPECTED_TOKEN, - _unexpected_token, stmt, token); - } - } else { - // collect tokens for field expression - if (exprstart) { - exprlen++; - } else { - exprstart = token; - exprlen = 1; - } - } + step = dav_parse_fieldlist(stmt, token, &state_fieldlist); break; } // from clause @@ -828,13 +934,9 @@ void dav_free_statement(DavQLStatement *stmt) { UCX_FOREACH(expr, stmt->fields) { - dav_free_expression(expr->data); + dav_free_field(expr->data); } ucx_list_free(stmt->fields); - UCX_FOREACH(expr, stmt->setvalues) { - dav_free_expression(expr->data); - } - ucx_list_free(stmt->setvalues); if (stmt->where) { dav_free_expression(stmt->where);
--- a/libidav/davqlparser.h Fri Apr 17 16:26:53 2015 +0200 +++ b/libidav/davqlparser.h Tue Apr 21 12:13:41 2015 +0200 @@ -46,6 +46,7 @@ * Enumeration of possible expression types. */ typedef enum { + DAVQL_UNDEFINED_TYP, DAVQL_NUMBER, DAVQL_STRING, DAVQL_TIMESTAMP, DAVQL_IDENTIFIER, DAVQL_UNARY, DAVQL_BINARY, DAVQL_LOGICAL, DAVQL_FUNCCALL } davqlexprtype_t; @@ -111,6 +112,27 @@ _Bool descending; } DavQLOrderCriterion; +/** + * A tuple representing a field. + */ +typedef struct { + /** + * The field name. + * <ul> + * <li>GET: the identifier or an alias name</li> + * <li>SET: the identifier</li> + * </ul> + */ + sstr_t name; + /** + * The field expression. + * <ul> + * <li>GET: the queried property (identifier) or an expression</li> + * <li>SET: the expression for the value to be set</li> + * </ul> + */ + DavQLExpression *expr; +} DavQLField; /** * Query statement object. @@ -145,11 +167,11 @@ * LogicalOperator = " and " | " or " | " xor "; * Comparison = | "=" | "<" | ">" | "<=" | ">=" | "!="; * - * FieldExpressions = "*", {",", Expression, " as ", String} + * FieldExpressions = "*", {",", Expression, " as ", Identifier} * | FieldExpression, {",", FieldExpression} * | "-"; * FieldExpression = Identifier - * | Expression, " as ", String; + * | Expression, " as ", Identifier; * SetExpressions = SetExpression, {",", SetExpressions}; * SetExpression = Identifier, "=", Expression; * @@ -204,15 +226,10 @@ */ char* errormessage; /** - * The list of field expressions. + * The list of DavQLFields. */ UcxList* fields; /** - * The list of DavQLExpressions for the new DAV property values. - * This is <code>NULL</code> for GET queries. - */ - UcxList* setvalues; - /** * A string that denotes the queried path. */ sstr_t path;