From 6a50bef84ae6a0a67e03ac1356f8d85d15fe09d6 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 19 Jan 2011 23:12:37 +0000 Subject: Merge parser autogeneration and string handling refactor branch r=jmb,kinnison,vince svn path=/trunk/libcss/; revision=11408 --- src/parse/properties/css_property_parser_gen.c | 613 +++++++++++++++++++++++++ 1 file changed, 613 insertions(+) create mode 100644 src/parse/properties/css_property_parser_gen.c (limited to 'src/parse/properties/css_property_parser_gen.c') diff --git a/src/parse/properties/css_property_parser_gen.c b/src/parse/properties/css_property_parser_gen.c new file mode 100644 index 0000000..a348c6a --- /dev/null +++ b/src/parse/properties/css_property_parser_gen.c @@ -0,0 +1,613 @@ +/* + * This file generates parts of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2010 Vincent Sanders + */ + +#include +#include +#include +#include + +/* Descriptors are space separated key:value pairs brackets () are + * used to quote in values. + * + * Examples: + * list_style_image:CSS_PROP_LIST_STYLE_IMAGE IDENT:( INHERIT: NONE:0,LIST_STYLE_IMAGE_NONE IDENT:) URI:LIST_STYLE_IMAGE_URI + * + * list_style_position:CSS_PROP_LIST_STYLE_POSITION IDENT:( INHERIT: INSIDE:0,LIST_STYLE_POSITION_INSIDE OUTSIDE:0,LIST_STYLE_POSITION_OUTSIDE IDENT:) +*/ + +struct keyval { + char *key; + char *val; +}; + +struct keyval_list { + struct keyval *item[100]; + int count; +}; + +struct keyval *get_keyval(char **pos) +{ + char *endpos; + struct keyval *nkeyval; + int kvlen; + + endpos = strchr(*pos, ' '); /* single space separated pairs */ + if (endpos == NULL) { + /* no space, but might be the end of the input */ + kvlen = strlen(*pos); + if (kvlen == 0) + return NULL; + endpos = *pos + kvlen; + } else { + kvlen = (endpos - *pos); + } + nkeyval = calloc(1, sizeof(struct keyval) + kvlen + 1); + + memcpy(nkeyval + 1, *pos, kvlen); + + nkeyval->key = (char *)nkeyval + sizeof(struct keyval); + + endpos = strchr(nkeyval->key, ':'); /* split key and value on : */ + if (endpos != NULL) { + endpos[0] = 0; /* change : to null terminator */ + nkeyval->val = endpos + 1; /* skip : */ + } + + *pos += kvlen; /* update position */ + + /* skip spaces */ + while ((*pos[0] != 0) && + (*pos[0] == ' ')) { + (*pos)++; + } + + return nkeyval; +} + +void output_header(FILE *outputf, const char *descriptor, struct keyval *parser_id, bool is_generic) +{ + fprintf(outputf, + "/*\n" + " * This file was generated by LibCSS gen_parser \n" + " * \n" + " * Generated from:\n" + " *\n" + " * %s\n" + " * \n" + " * Licensed under the MIT License,\n" + " * http://www.opensource.org/licenses/mit-license.php\n" + " * Copyright 2010 The NetSurf Browser Project.\n" + " */\n" + "\n" + "#include \n" + "#include \n" + "\n" + "#include \"bytecode/bytecode.h\"\n" + "#include \"bytecode/opcodes.h\"\n" + "#include \"parse/properties/properties.h\"\n" + "#include \"parse/properties/utils.h\"\n" + "\n" + "/**\n" + " * Parse %s\n" + " *\n" + " * \\param c Parsing context\n" + " * \\param vector Vector of tokens to process\n" + " * \\param ctx Pointer to vector iteration context\n" + " * \\param result resulting style\n" + "%s" + " * \\return CSS_OK on success,\n" + " * CSS_NOMEM on memory exhaustion,\n" + " * CSS_INVALID if the input is not valid\n" + " *\n" + " * Post condition: \\a *ctx is updated with the next token to process\n" + " * If the input is invalid, then \\a *ctx remains unchanged.\n" + " */\n" + "css_error parse_%s(css_language *c,\n" + " const parserutils_vector *vector, int *ctx,\n" + " css_style *result%s)\n" + "{\n", + descriptor, + parser_id->key, + is_generic ? " * \\param op Bytecode OpCode for CSS property to encode\n" : "", + parser_id->key, + is_generic ? ", enum css_properties_e op" : ""); +} + + +void output_token_type_check(FILE *outputf, bool do_token_check, struct keyval_list *IDENT, struct keyval_list *URI, struct keyval_list *NUMBER) +{ + fprintf(outputf, + " int orig_ctx = *ctx;\n" + " css_error error;\n" + " const css_token *token;\n" + " bool match;\n\n" + " token = parserutils_vector_iterate(vector, ctx);\n" + " if ((token == NULL)"); + + if (do_token_check) { + bool prev = false; /* there was a previous check - add && */ + fprintf(outputf," || ("); + + if (IDENT->count > 0) { + fprintf(outputf,"(token->type != CSS_TOKEN_IDENT)"); + prev = true; + } + if (URI->count > 0) { + if (prev) fprintf(outputf," && "); + fprintf(outputf,"(token->type != CSS_TOKEN_URI)"); + prev = true; + } + if (NUMBER->count > 0) { + if (prev) fprintf(outputf," && "); + fprintf(outputf,"(token->type != CSS_TOKEN_NUMBER)"); + prev = true; + } + + fprintf(outputf,")"); + } + + fprintf(outputf, + ") {\n" + "\t\t*ctx = orig_ctx;\n" + "\t\treturn CSS_INVALID;\n" + "\t}\n\n\t"); +} + +void output_ident(FILE *outputf, bool only_ident, struct keyval *parseid, struct keyval_list *IDENT) +{ + int ident_count; + + for (ident_count = 0 ; ident_count < IDENT->count; ident_count++) { + struct keyval *ckv = IDENT->item[ident_count]; + + fprintf(outputf, + "if ("); + if (!only_ident) { + fprintf(outputf, + "(token->type == CSS_TOKEN_IDENT) && "); + } + fprintf(outputf, + "(lwc_string_caseless_isequal(token->idata, c->strings[%s], &match) == lwc_error_ok && match)) {\n", + ckv->key); + if (strcmp(ckv->key,"INHERIT") == 0) { + fprintf(outputf, + "\t\t\terror = css_stylesheet_style_inherit(result, %s);\n", + parseid->val); + } else { + fprintf(outputf, + "\t\t\terror = css_stylesheet_style_appendOPV(result, %s, %s);\n", + parseid->val, + ckv->val); + } + fprintf(outputf, + "\t} else "); + } +} + +void output_uri(FILE *outputf, struct keyval *parseid, struct keyval_list *kvlist) +{ + struct keyval *ckv = kvlist->item[0]; + + fprintf(outputf, + "if (token->type == CSS_TOKEN_URI) {\n" + " lwc_string *uri = NULL;\n" + " uint32_t uri_snumber;\n" + "\n" + " error = c->sheet->resolve(c->sheet->resolve_pw,\n" + " c->sheet->url,\n" + " token->idata, &uri);\n" + " if (error != CSS_OK) {\n" + " *ctx = orig_ctx;\n" + " return error;\n" + " }\n" + "\n" + " error = css_stylesheet_string_add(c->sheet, uri, &uri_snumber);\n" + " if (error != CSS_OK) {\n" + " *ctx = orig_ctx;\n" + " return error;\n" + " }\n" + "\n" + " error = css_stylesheet_style_appendOPV(result, %s, 0, %s);\n" + " if (error != CSS_OK) {\n" + " *ctx = orig_ctx;\n" + " return error;\n" + " }\n" + "\n" + " error = css_stylesheet_style_append(result, uri_snumber);\n" + " } else ", + parseid->val, + ckv->val); +} + +void output_number(FILE *outputf, struct keyval *parseid, struct keyval_list *kvlist) +{ + struct keyval *ckv = kvlist->item[0]; + int ident_count; + + fprintf(outputf, + "if (token->type == CSS_TOKEN_NUMBER) {\n" + "\t\tcss_fixed num = 0;\n" + "\t\tsize_t consumed = 0;\n\n" + "\t\tnum = number_from_lwc_string(token->idata, %s, &consumed);\n" + "\t\t/* Invalid if there are trailing characters */\n" + "\t\tif (consumed != lwc_string_length(token->idata)) {\n" + "\t\t\t*ctx = orig_ctx;\n" + "\t\t\treturn CSS_INVALID;\n" + "\t\t}\n", + ckv->key); + + for (ident_count = 1 ; ident_count < kvlist->count; ident_count++) { + struct keyval *ulkv = kvlist->item[ident_count]; + + if (strcmp(ulkv->key, "RANGE") == 0) { + fprintf(outputf, + "\t\tif (%s) {\n" + "\t\t\t*ctx = orig_ctx;\n" + "\t\t\treturn CSS_INVALID;\n" + "\t\t}\n\n", + ulkv->val); + } + + } + + fprintf(outputf, + "\t\terror = css_stylesheet_style_appendOPV(result, %s, 0, %s);\n" + "\t\tif (error != CSS_OK) {\n" + "\t\t\t*ctx = orig_ctx;\n" + "\t\t\treturn error;\n" + "\t\t}\n\n" + "\t\terror = css_stylesheet_style_append(result, num);\n" + "\t} else ", + parseid->val, + ckv->val); +} + +void output_color(FILE *outputf, struct keyval *parseid, struct keyval_list *kvlist) +{ + struct keyval *ckv = kvlist->item[0]; + + fprintf(outputf, + "{\n" + "\t\tuint32_t color = 0;\n" + "\t\t*ctx = orig_ctx;\n\n" + "\t\terror = parse_colour_specifier(c, vector, ctx, &color);\n" + "\t\tif (error != CSS_OK) {\n" + "\t\t\t*ctx = orig_ctx;\n" + "\t\t\treturn error;\n" + "\t\t}\n\n" + "\t\terror = css_stylesheet_style_appendOPV(result, %s, 0, %s);\n" + "\t\tif (error != CSS_OK) {\n" + "\t\t\t*ctx = orig_ctx;\n" + "\t\t\treturn error;\n" + "\t\t}\n" + "\n" + "\t\terror = css_stylesheet_style_append(result, color);\n" + "\t}\n\n", + parseid->val, + ckv->val); +} + +void output_length_unit(FILE *outputf, struct keyval *parseid, struct keyval_list *kvlist) +{ + struct keyval *ckv = kvlist->item[0]; + int ident_count; + + + fprintf(outputf, + "{\n" + "\t\tcss_fixed length = 0;\n" + "\t\tuint32_t unit = 0;\n" + "\t\t*ctx = orig_ctx;\n\n" + "\t\terror = parse_unit_specifier(c, vector, ctx, %s, &length, &unit);\n" + "\t\tif (error != CSS_OK) {\n" + "\t\t\t*ctx = orig_ctx;\n" + "\t\t\treturn error;\n" + "\t\t}\n\n", + ckv->key); + + for (ident_count = 1 ; ident_count < kvlist->count; ident_count++) { + struct keyval *ulkv = kvlist->item[ident_count]; + + if (strcmp(ulkv->key, "ALLOW") == 0) { + fprintf(outputf, + "\t\tif ((%s) == false) {\n" + "\t\t\t*ctx = orig_ctx;\n" + "\t\t\treturn CSS_INVALID;\n" + "\t\t}\n\n", + ulkv->val); + } else if (strcmp(ulkv->key, "DISALLOW") == 0) { + fprintf(outputf, + "\t\tif (%s) {\n" + "\t\t\t*ctx = orig_ctx;\n" + "\t\t\treturn CSS_INVALID;\n" + "\t\t}\n\n", + ulkv->val); + } else if (strcmp(ulkv->key, "RANGE") == 0) { + fprintf(outputf, + "\t\tif (length %s) {\n" + "\t\t\t*ctx = orig_ctx;\n" + "\t\t\treturn CSS_INVALID;\n" + "\t\t}\n\n", + ulkv->val); + } + + } + + fprintf(outputf, + "\t\terror = css_stylesheet_style_appendOPV(result, %s, 0, %s);\n" + "\t\tif (error != CSS_OK) {\n" + "\t\t\t*ctx = orig_ctx;\n" + "\t\t\treturn error;\n" + "\t\t}\n" + "\n" + "\t\terror = css_stylesheet_style_vappend(result, 2, length, unit);\n" + "\t}\n\n", + parseid->val, + ckv->val); +} + +void output_ident_list(FILE *outputf, struct keyval *parseid, struct keyval_list *kvlist) +{ + struct keyval *ckv = kvlist->item[0]; /* list type : opv value */ + if (strcmp(ckv->key, "STRING_OPTNUM") == 0) { + /* list of IDENT and optional numbers */ + struct keyval *ikv = kvlist->item[1]; /* numeric default : end condition */ + + fprintf(outputf, + "{\n" + "\t\terror = css_stylesheet_style_appendOPV(result, %s, 0, %s);\n" + "\t\tif (error != CSS_OK) {\n" + "\t\t\t*ctx = orig_ctx;\n" + "\t\t\treturn error;\n" + "\t\t}\n\n" + "\t\twhile ((token != NULL) && (token->type == CSS_TOKEN_IDENT)) {\n" + "\t\t\tuint32_t snumber;\n" + "\t\t\tcss_fixed num;\n" + "\t\t\tint pctx;\n\n" + "\t\t\terror = css_stylesheet_string_add(c->sheet, lwc_string_ref(token->idata), &snumber);\n" + "\t\t\tif (error != CSS_OK) {\n" + "\t\t\t\t*ctx = orig_ctx;\n" + "\t\t\t\treturn error;\n" + "\t\t\t}\n\n" + "\t\t\terror = css_stylesheet_style_append(result, snumber);\n" + "\t\t\tif (error != CSS_OK) {\n" + "\t\t\t\t*ctx = orig_ctx;\n" + "\t\t\t\treturn error;\n" + "\t\t\t}\n\n" + "\t\t\tconsumeWhitespace(vector, ctx);\n\n" + "\t\t\tpctx = *ctx;\n" + "\t\t\ttoken = parserutils_vector_iterate(vector, ctx);\n" + "\t\t\tif ((token != NULL) && (token->type == CSS_TOKEN_NUMBER)) {\n" + "\t\t\t\tsize_t consumed = 0;\n\n" + "\t\t\t\tnum = number_from_lwc_string(token->idata, true, &consumed);\n" + "\t\t\t\tif (consumed != lwc_string_length(token->idata)) {\n" + "\t\t\t\t\t*ctx = orig_ctx;\n" + "\t\t\t\t\treturn CSS_INVALID;\n" + "\t\t\t\t}\n" + "\t\t\t\tconsumeWhitespace(vector, ctx);\n\n" + "\t\t\t\tpctx = *ctx;\n" + "\t\t\t\ttoken = parserutils_vector_iterate(vector, ctx);\n" + "\t\t\t} else {\n" + "\t\t\t\tnum = INTTOFIX(%s);\n" + "\t\t\t}\n\n" + "\t\t\terror = css_stylesheet_style_append(result, num);\n" + "\t\t\tif (error != CSS_OK) {\n" + "\t\t\t\t*ctx = orig_ctx;\n" + "\t\t\t\treturn error;\n" + "\t\t\t}\n\n" + "\t\t\tif (token == NULL)\n" + "\t\t\t\tbreak;\n\n" + "\t\t\tif (token->type == CSS_TOKEN_IDENT) {\n" + "\t\t\t\terror = css_stylesheet_style_append(result, %s);\n" + "\t\t\t\tif (error != CSS_OK) {\n" + "\t\t\t\t\t*ctx = orig_ctx;\n" + "\t\t\t\t\treturn error;\n" + "\t\t\t\t}\n" + "\t\t\t} else {\n" + "\t\t\t\t*ctx = pctx; /* rewind one token back */\n" + "\t\t\t}\n" + "\t\t}\n\n" + "\t\terror = css_stylesheet_style_append(result, %s);\n" + "\t}\n\n", + parseid->val, + ckv->val, + ikv->key, + ckv->val, + ikv->val); + + } else { + fprintf(stderr, "unknown IDENT list type %s\n",ckv->key); + exit(4); + } + +} + +void output_invalidcss(FILE *outputf) +{ + fprintf(outputf, "{\n\t\terror = CSS_INVALID;\n\t}\n\n"); +} + +void output_footer(FILE *outputf) +{ + fprintf(outputf, + " if (error != CSS_OK)\n" + " *ctx = orig_ctx;\n" + " \n" + " return error;\n" + "}\n\n"); +} + +void output_wrap(FILE *outputf, struct keyval *parseid, struct keyval_list *WRAP) +{ + struct keyval *ckv = WRAP->item[0]; + fprintf(outputf, + " return %s(c, vector, ctx, result, %s);\n}\n", + ckv->val, + parseid->val); +} + +char str_INHERIT[] = "INHERIT"; + +struct keyval ident_inherit = { + .key = str_INHERIT, +}; + +int main(int argc, char **argv) +{ + char *descriptor; + char *curpos; /* current position in input string */ + struct keyval *parser_id; /* the parser we are creating output for */ + FILE *outputf; + struct keyval *rkv; /* current read key:val */ + struct keyval_list *curlist; + bool do_token_check = true; /* if the check for valid tokens is done */ + bool only_ident = true; /* if the only token type is ident */ + bool is_generic = false; + + struct keyval_list base; + struct keyval_list IDENT; + struct keyval_list IDENT_LIST; + struct keyval_list LENGTH_UNIT; + struct keyval_list URI; + struct keyval_list WRAP; + struct keyval_list NUMBER; + struct keyval_list COLOR; + + + if (argc < 2) { + fprintf(stderr,"Usage: %s [-o ] \n", argv[0]); + return 1; + } + + if ((argv[1][0] == '-') && (argv[1][1] == 'o')) { + if (argc != 4) { + fprintf(stderr,"Usage: %s [-o ] \n", argv[0]); + return 1; + } + outputf = fopen(argv[2], "w"); + if (outputf == NULL) { + perror("unable to open file"); + } + descriptor = strdup(argv[3]); + } else { + outputf = stdout; + descriptor = strdup(argv[1]); + } + curpos = descriptor; + + base.count = 0; + IDENT.count = 0; + URI.count = 0; + WRAP.count = 0; + NUMBER.count = 0; + COLOR.count = 0; + LENGTH_UNIT.count = 0; + IDENT_LIST.count = 0; + + curlist = &base; + + while (*curpos != 0) { + rkv = get_keyval(&curpos); + if (rkv == NULL) { + fprintf(stderr,"Token error at offset %ld\n", curpos - descriptor); + fclose(outputf); + return 2; + } + + if (strcmp(rkv->key, "WRAP") == 0) { + WRAP.item[WRAP.count++] = rkv; + only_ident = false; + } else if (strcmp(rkv->key, "NUMBER") == 0) { + if (rkv->val[0] == '(') { + curlist = &NUMBER; + } else if (rkv->val[0] == ')') { + curlist = &base; + } else { + NUMBER.item[NUMBER.count++] = rkv; + } + only_ident = false; + } else if (strcmp(rkv->key, "IDENT") == 0) { + if (rkv->val[0] == '(') { + curlist = &IDENT; + } else if (rkv->val[0] == ')') { + curlist = &base; + } else if (strcmp(rkv->val, str_INHERIT) == 0) { + IDENT.item[IDENT.count++] = &ident_inherit; + } + } else if (strcmp(rkv->key, "IDENT_LIST") == 0) { + if (rkv->val[0] == '(') { + curlist = &IDENT_LIST; + } else if (rkv->val[0] == ')') { + curlist = &base; + } + } else if (strcmp(rkv->key, "LENGTH_UNIT") == 0) { + if (rkv->val[0] == '(') { + curlist = &LENGTH_UNIT; + } else if (rkv->val[0] == ')') { + curlist = &base; + } + only_ident = false; + do_token_check = false; + } else if (strcmp(rkv->key, "COLOR") == 0) { + COLOR.item[COLOR.count++] = rkv; + do_token_check = false; + only_ident = false; + } else if (strcmp(rkv->key, "URI") == 0) { + URI.item[URI.count++] = rkv; + only_ident = false; + } else if (strcmp(rkv->key, "GENERIC") == 0) { + is_generic = true; + } else { + /* just append to current list */ + curlist->item[curlist->count++] = rkv; + } + } + + if (base.count != 1) { + fprintf(stderr,"Incorrect base element count (got %d expected 1)\n", base.count); + fclose(outputf); + return 3; + } + + + /* header */ +output_header(outputf, descriptor, base.item[0], is_generic); + + if (WRAP.count > 0) { + output_wrap(outputf, base.item[0], &WRAP); + } else { + /* check token type is correct */ + output_token_type_check(outputf, do_token_check, &IDENT, &URI, &NUMBER); + + if (IDENT.count > 0) + output_ident(outputf, only_ident, base.item[0], &IDENT); + + if (URI.count > 0) + output_uri(outputf, base.item[0], &URI); + + if (NUMBER.count > 0) + output_number(outputf, base.item[0], &NUMBER); + + /* terminal blocks, these end the ladder ie no trailing else */ + if (COLOR.count > 0) { + output_color(outputf, base.item[0], &COLOR); + } else if (LENGTH_UNIT.count > 0) { + output_length_unit(outputf, base.item[0], &LENGTH_UNIT); + } else if (IDENT_LIST.count > 0) { + output_ident_list(outputf, base.item[0], &IDENT_LIST); + } else { + output_invalidcss(outputf); + } + + output_footer(outputf); + + } + + fclose(outputf); + + return 0; +} -- cgit v1.2.3