diff options
Diffstat (limited to 'src/glsl')
-rw-r--r-- | src/glsl/pp/sl_pp_token.c | 250 |
1 files changed, 227 insertions, 23 deletions
diff --git a/src/glsl/pp/sl_pp_token.c b/src/glsl/pp/sl_pp_token.c index 95fe4f7d85e..a6a2bb27485 100644 --- a/src/glsl/pp/sl_pp_token.c +++ b/src/glsl/pp/sl_pp_token.c @@ -30,6 +30,13 @@ static int +_is_identifier_char(char c) +{ + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; +} + + +static int _tokenise_identifier(struct sl_pp_context *context, const char **pinput, struct sl_pp_token_info *info) @@ -42,10 +49,7 @@ _tokenise_identifier(struct sl_pp_context *context, info->data.identifier = -1; identifier[i++] = *input++; - while ((*input >= 'a' && *input <= 'z') || - (*input >= 'A' && *input <= 'Z') || - (*input >= '0' && *input <= '9') || - (*input == '_')) { + while (_is_identifier_char(*input)) { if (i >= sizeof(identifier) - 1) { strcpy(context->error_msg, "out of memory"); return -1; @@ -64,41 +68,241 @@ _tokenise_identifier(struct sl_pp_context *context, } +/* + * Return the number of consecutive decimal digits in the input stream. + */ +static unsigned int +_parse_float_digits(const char *input) +{ + unsigned int eaten = 0; + + while (input[eaten] >= '0' && input[eaten] <= '9') { + eaten++; + } + return eaten; +} + + +/* + * Try to match one of the following patterns for the fractional part + * of a floating point number. + * + * digits . [digits] + * . digits + * + * Return 0 if the pattern could not be matched, otherwise the number + * of eaten characters from the input stream. + */ +static unsigned int +_parse_float_frac(const char *input) +{ + unsigned int eaten; + + if (input[0] == '.') { + eaten = _parse_float_digits(&input[1]); + if (eaten) { + return eaten + 1; + } + return 0; + } + + eaten = _parse_float_digits(input); + if (eaten && input[eaten] == '.') { + unsigned int trailing; + + trailing = _parse_float_digits(&input[eaten + 1]); + if (trailing) { + return eaten + trailing + 1; + } + return eaten + 1; + } + + return 0; +} + + +/* + * Try to match the following pattern for the exponential part + * of a floating point number. + * + * (e|E) [(+|-)] digits + * + * Return 0 if the pattern could not be matched, otherwise the number + * of eaten characters from the input stream. + */ +static unsigned int +_parse_float_exp(const char *input) +{ + unsigned int eaten, digits; + + if (input[0] != 'e' && input[0] != 'E') { + return 0; + } + + if (input[1] == '-' || input[1] == '+') { + eaten = 2; + } else { + eaten = 1; + } + + digits = _parse_float_digits(&input[eaten]); + if (!digits) { + return 0; + } + + return eaten + digits; +} + + +/* + * Try to match one of the following patterns for a floating point number. + * + * fract [exp] [(f|F)] + * digits exp [(f|F)] + * + * Return 0 if the pattern could not be matched, otherwise the number + * of eaten characters from the input stream. + */ +static unsigned int +_parse_float(const char *input) +{ + unsigned int eaten; + + eaten = _parse_float_frac(input); + if (eaten) { + unsigned int exponent; + + exponent = _parse_float_exp(&input[eaten]); + if (exponent) { + eaten += exponent; + } + + if (input[eaten] == 'f' || input[eaten] == 'F') { + eaten++; + } + + return eaten; + } + + eaten = _parse_float_digits(input); + if (eaten) { + unsigned int exponent; + + exponent = _parse_float_exp(&input[eaten]); + if (exponent) { + eaten += exponent; + + if (input[eaten] == 'f' || input[eaten] == 'F') { + eaten++; + } + + return eaten; + } + } + + return 0; +} + + +static unsigned int +_parse_hex(const char *input) +{ + unsigned int n; + + if (input[0] != '0') { + return 0; + } + + if (input[1] != 'x' && input[1] != 'X') { + return 0; + } + + n = 2; + while ((input[n] >= '0' && input[n] <= '9') || + (input[n] >= 'a' && input[n] <= 'f') || + (input[n] >= 'A' && input[n] <= 'F')) { + n++; + } + + if (n > 2) { + return n; + } + + return 0; +} + + +static unsigned int +_parse_oct(const char *input) +{ + unsigned int n; + + if (input[0] != '0') { + return 0; + } + + n = 1; + while ((input[n] >= '0' && input[n] <= '7')) { + n++; + } + + return n; +} + + +static unsigned int +_parse_dec(const char *input) +{ + unsigned int n = 0; + + while ((input[n] >= '0' && input[n] <= '9')) { + n++; + } + + return n; +} + + static int _tokenise_number(struct sl_pp_context *context, const char **pinput, struct sl_pp_token_info *info) { const char *input = *pinput; + unsigned int eaten; char number[256]; /* XXX: Remove this artifical limit. */ - unsigned int i = 0; - info->token = SL_PP_NUMBER; - info->data.number = -1; - - number[i++] = *input++; - while ((*input >= '0' && *input <= '9') || - (*input >= 'a' && *input <= 'f') || - (*input >= 'A' && *input <= 'F') || - (*input == 'x') || - (*input == 'X') || - (*input == '+') || - (*input == '-') || - (*input == '.')) { - if (i >= sizeof(number) - 1) { - strcpy(context->error_msg, "out of memory"); - return -1; + eaten = _parse_float(input); + if (!eaten) { + eaten = _parse_hex(input); + if (!eaten) { + eaten = _parse_oct(input); + if (!eaten) { + eaten = _parse_dec(input); + } } - number[i++] = *input++; } - number[i++] = '\0'; + if (!eaten || _is_identifier_char(input[eaten])) { + strcpy(context->error_msg, "expected a number"); + return -1; + } + + if (eaten > sizeof(number) - 1) { + strcpy(context->error_msg, "out of memory"); + return -1; + } + + memcpy(number, input, eaten); + number[eaten] = '\0'; + + info->token = SL_PP_NUMBER; info->data.number = sl_pp_context_add_unique_str(context, number); if (info->data.number == -1) { return -1; } - *pinput = input; + *pinput = input + eaten; return 0; } |