/** @brief Collect characters into a number, and create a JSON_NUMBER for it. @param parser Pointer to a parser. @param firstc The first character in the number. @return Pointer to a newly created jsonObject of type JSON_NUMBER, or NULL upon error. Collect digits, signs, decimal points, and 'E' or 'e' (for scientific notation) into a buffer. Make sure that the result is numeric. If it's not numeric by strict JSON rules, try to make it numeric by some judicious massaging (we aren't quite as strict as the official JSON rules). If successful, construct a jsonObject of type JSON_NUMBER containing the resulting numeric string. Otherwise log an error message and return NULL. */ static jsonObject* get_number( Parser* parser, char firstc ) { if( parser->str_buf ) buffer_reset( parser->str_buf ); else parser->str_buf = buffer_init( 64 ); growing_buffer* gb = parser->str_buf; OSRF_BUFFER_ADD_CHAR( gb, firstc ); char c; for( ;; ) { c = parser_nextc( parser ); if( isdigit( (unsigned char) c ) || '.' == c || '-' == c || '+' == c || 'e' == c || 'E' == c ) { OSRF_BUFFER_ADD_CHAR( gb, c ); } else { if( ! isspace( (unsigned char) c ) ) parser_ungetc( parser ); break; } } char* s = buffer_data( gb ); if( ! jsonIsNumeric( s ) ) { char* temp = jsonScrubNumber( s ); free( s ); s = temp; if( !s ) { report_error( parser, parser->buff[ parser->index - 1 ], "Invalid numeric format" ); return NULL; } } jsonObject* obj = jsonNewObject( NULL ); obj->type = JSON_NUMBER; obj->value.s = s; return obj; }
/** @brief Parse the JSON keyword "true", and create a JSON_BOOL for it. @param parser Pointer to a Parser. @return Pointer to a newly created jsonObject of type JSON_BOOL, or NULL upon error. We already saw a 't', or we wouldn't be here. Make sure that the next three characters are 'r', 'u', and 'e', and that the character after that is not a letter or a digit. If all goes well, create a jsonObject of type JSON_BOOL, and return a pointer to it. Otherwise log an error message and return NULL. */ static jsonObject* get_true( Parser* parser ) { if( parser_nextc( parser ) != 'r' || parser_nextc( parser ) != 'u' || parser_nextc( parser ) != 'e' ) { report_error( parser, parser->buff[ parser->index - 1 ], "Expected \"rue\" to follow \"t\"; didn't find it" ); return NULL; } // Peek at the next character to make sure that it's kosher char c = parser_nextc( parser ); if( ! isspace( (unsigned char) c ) ) parser_ungetc( parser ); if( isalnum( (unsigned char) c ) ) { report_error( parser, c, "Found letter or number after \"true\"" ); return NULL; } // Everything's okay. Return a JSON_BOOL. return jsonNewBoolObject( 1 ); }
void lex (parser *p) { #if LDEBUG if (p->ch) fprintf(stderr, "lex: p->ch = '%c'\n", p->ch); else fprintf(stderr, "lex: p->ch = NUL\n"); #endif if (p->ch == 0) { p->sym = EOT; return; } while (p->ch != 0) { switch (p->ch) { case ' ': case '\t': case '\r': case '\n': parser_getc(p); break; case '+': p->sym = B_ADD; parser_getc(p); return; case '-': p->sym = B_SUB; parser_getc(p); return; case '*': if (p->targ == LIST) { /* treat '*' as wildcard */ getword(p); return; } parser_getc(p); if (p->ch == '*') { p->sym = B_KRON; parser_getc(p); } else { p->sym = B_MUL; } return; case '\'': p->sym = B_TRMUL; parser_getc(p); return; case '/': p->sym = B_DIV; parser_getc(p); return; case '\\': p->sym = B_LDIV; parser_getc(p); return; case '%': p->sym = B_MOD; parser_getc(p); return; case '^': p->sym = B_POW; parser_getc(p); return; case '&': parser_getc(p); if (p->ch == '&') { p->sym = B_AND; parser_getc(p); } else { p->sym = U_ADDR; } return; case '|': parser_getc(p); if (p->ch == '|') { p->sym = B_OR; parser_getc(p); } else { p->sym = B_VCAT; } return; case '!': parser_getc(p); if (p->ch == '=') { p->sym = B_NEQ; parser_getc(p); } else { p->sym = U_NOT; } return; case '=': parser_getc(p); if (p->ch == '=') { /* allow "==" as synonym for "=" */ parser_getc(p); } p->sym = B_EQ; return; case '>': parser_getc(p); if (p->ch == '=') { p->sym = B_GTE; parser_getc(p); } else { p->sym = B_GT; } return; case '<': parser_getc(p); if (p->ch == '=') { p->sym = B_LTE; parser_getc(p); } else if (p->ch == '>') { p->sym = B_NEQ; parser_getc(p); } else { p->sym = B_LT; } return; case '(': p->sym = G_LPR; parser_getc(p); return; case ')': p->sym = G_RPR; parser_getc(p); return; case '[': p->sym = G_LBR; parser_getc(p); return; case '{': p->sym = G_LCB; parser_getc(p); return; case '}': p->sym = G_RCB; parser_getc(p); return; case ']': p->sym = G_RBR; parser_getc(p); return; case '~': p->sym = B_HCAT; parser_getc(p); return; case ',': p->sym = P_COM; parser_getc(p); return; case ';': if (p->targ == LIST) { p->sym = B_JOIN; } else { /* used in matrix definition */ p->sym = P_SEMI; } parser_getc(p); return; case ':': p->sym = P_COL; parser_getc(p); return; case '?': p->sym = QUERY; parser_getc(p); return; case '.': if (*p->point == '$') { p->sym = P_DOT; parser_getc(p); return; } parser_getc(p); if (p->ch == '*') { p->sym = B_DOTMULT; parser_getc(p); return; } else if (p->ch == '/') { p->sym = B_DOTDIV; parser_getc(p); return; } else if (p->ch == '^') { p->sym = B_DOTPOW; parser_getc(p); return; } else if (p->ch == '+') { p->sym = B_DOTADD; parser_getc(p); return; } else if (p->ch == '-') { p->sym = B_DOTSUB; parser_getc(p); return; } else if (p->ch == '=') { p->sym = B_DOTEQ; parser_getc(p); return; } else if (p->ch == '>') { p->sym = B_DOTGT; parser_getc(p); if (p->ch == '=') { p->sym = B_DOTGTE; parser_getc(p); } return; } else if (p->ch == '<') { p->sym = B_DOTLT; parser_getc(p); if (p->ch == '=') { p->sym = B_DOTLTE; parser_getc(p); } return; } else if (p->ch == '.') { p->sym = B_ELLIP; parser_getc(p); return; } else { /* not a "dot operator", so back up */ parser_ungetc(p); } default: if (p->targ == LIST && lag_range_sym(p)) { p->sym = B_RANGE; parser_getc(p); parser_getc(p); return; } if (p->targ == LIST && *(p->point - 2) == ' ' && (bare_data_type(p->sym) || closing_sym(p->sym) || (p->sym == LAG))) { /* may be forming a list, but only if there are spaces between the terms */ p->sym = B_LCAT; return; } if (isdigit(p->ch) || (p->ch == '.' && isdigit(*p->point))) { parse_number(p); return; } else if (islower(p->ch) || isupper(p->ch) || word_start_special(p->ch)) { getword(p); return; } else if (p->ch == '"') { p->idstr = get_quoted_string(p); return; } else { parser_print_input(p); pprintf(p->prn, _("Invalid character '%c'\n"), p->ch); p->err = E_PARSE; return; } } /* end ch switch */ } /* end while ch != 0 */ }