diff options
author | sanine <sanine.not@pm.me> | 2023-02-03 22:34:04 -0600 |
---|---|---|
committer | sanine <sanine.not@pm.me> | 2023-02-03 22:34:04 -0600 |
commit | ea512c3b1d2d85ff76aa7d4979c73dd7f1217757 (patch) | |
tree | c5bd7d5151a86ae4a54a3241fe745c0e2dd64d58 | |
parent | 0710a40e50d12cd731b0372d79d0ccdfbaee10d4 (diff) |
begin refactor with bison xml parser
-rw-r--r-- | 3rdparty/ezxml/CMakeLists.txt | 4 | ||||
-rw-r--r-- | 3rdparty/ezxml/ezxml.c | 1015 | ||||
-rw-r--r-- | 3rdparty/ezxml/ezxml.h | 167 | ||||
-rw-r--r-- | 3rdparty/stb_ds.h | 1895 | ||||
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/geometry/geometry.c | 36 | ||||
-rw-r--r-- | src/geometry/geometry.h | 3 | ||||
-rw-r--r-- | src/geometry/geometry.test.c | 30 | ||||
-rw-r--r-- | src/xml/CMakeLists.txt | 7 | ||||
-rw-r--r-- | src/xml/kalmia.lex.c | 2343 | ||||
-rw-r--r-- | src/xml/kalmia.lex.h | 735 | ||||
-rw-r--r-- | src/xml/kalmia.tab.c | 2001 | ||||
-rw-r--r-- | src/xml/kalmia.tab.h | 141 | ||||
-rw-r--r-- | src/xml/xml.c | 20 | ||||
-rw-r--r-- | src/xml/xml.h | 11 | ||||
-rw-r--r-- | yy/demo.c (renamed from yy/main.c) | 0 | ||||
-rw-r--r-- | yy/makefile | 8 |
18 files changed, 5264 insertions, 3157 deletions
diff --git a/3rdparty/ezxml/CMakeLists.txt b/3rdparty/ezxml/CMakeLists.txt deleted file mode 100644 index db024d9..0000000 --- a/3rdparty/ezxml/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -cmake_minimum_required(VERSION 3.2) -project(ezxml) - -add_library(ezxml STATIC ezxml.c) diff --git a/3rdparty/ezxml/ezxml.c b/3rdparty/ezxml/ezxml.c deleted file mode 100644 index 82b11fb..0000000 --- a/3rdparty/ezxml/ezxml.c +++ /dev/null @@ -1,1015 +0,0 @@ -/* ezxml.c - * - * Copyright 2004-2006 Aaron Voisine <aaron@voisine.org> - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <stdarg.h> -#include <string.h> -#include <ctype.h> -#include <unistd.h> -#include <sys/types.h> -#ifndef EZXML_NOMMAP -#include <sys/mman.h> -#endif // EZXML_NOMMAP -#include <sys/stat.h> -#include "ezxml.h" - -#define EZXML_WS "\t\r\n " // whitespace -#define EZXML_ERRL 128 // maximum error string length - -typedef struct ezxml_root *ezxml_root_t; -struct ezxml_root { // additional data for the root tag - struct ezxml xml; // is a super-struct built on top of ezxml struct - ezxml_t cur; // current xml tree insertion point - char *m; // original xml string - size_t len; // length of allocated memory for mmap, -1 for malloc - char *u; // UTF-8 conversion of string if original was UTF-16 - char *s; // start of work area - char *e; // end of work area - char **ent; // general entities (ampersand sequences) - char ***attr; // default attributes - char ***pi; // processing instructions - short standalone; // non-zero if <?xml standalone="yes"?> - char err[EZXML_ERRL]; // error string -}; - -char *EZXML_NIL[] = { NULL }; // empty, null terminated array of strings - -// returns the first child tag with the given name or NULL if not found -ezxml_t ezxml_child(ezxml_t xml, const char *name) -{ - xml = (xml) ? xml->child : NULL; - while (xml && strcmp(name, xml->name)) xml = xml->sibling; - return xml; -} - -// returns the Nth tag with the same name in the same subsection or NULL if not -// found -ezxml_t ezxml_idx(ezxml_t xml, int idx) -{ - for (; xml && idx; idx--) xml = xml->next; - return xml; -} - -// returns the value of the requested tag attribute or NULL if not found -const char *ezxml_attr(ezxml_t xml, const char *attr) -{ - int i = 0, j = 1; - ezxml_root_t root = (ezxml_root_t)xml; - - if (! xml || ! xml->attr) return NULL; - while (xml->attr[i] && strcmp(attr, xml->attr[i])) i += 2; - if (xml->attr[i]) return xml->attr[i + 1]; // found attribute - - while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag - for (i = 0; root->attr[i] && strcmp(xml->name, root->attr[i][0]); i++); - if (! root->attr[i]) return NULL; // no matching default attributes - while (root->attr[i][j] && strcmp(attr, root->attr[i][j])) j += 3; - return (root->attr[i][j]) ? root->attr[i][j + 1] : NULL; // found default -} - -// same as ezxml_get but takes an already initialized va_list -ezxml_t ezxml_vget(ezxml_t xml, va_list ap) -{ - char *name = va_arg(ap, char *); - int idx = -1; - - if (name && *name) { - idx = va_arg(ap, int); - xml = ezxml_child(xml, name); - } - return (idx < 0) ? xml : ezxml_vget(ezxml_idx(xml, idx), ap); -} - -// Traverses the xml tree to retrieve a specific subtag. Takes a variable -// length list of tag names and indexes. The argument list must be terminated -// by either an index of -1 or an empty string tag name. Example: -// title = ezxml_get(library, "shelf", 0, "book", 2, "title", -1); -// This retrieves the title of the 3rd book on the 1st shelf of library. -// Returns NULL if not found. -ezxml_t ezxml_get(ezxml_t xml, ...) -{ - va_list ap; - ezxml_t r; - - va_start(ap, xml); - r = ezxml_vget(xml, ap); - va_end(ap); - return r; -} - -// returns a null terminated array of processing instructions for the given -// target -const char **ezxml_pi(ezxml_t xml, const char *target) -{ - ezxml_root_t root = (ezxml_root_t)xml; - int i = 0; - - if (! root) return (const char **)EZXML_NIL; - while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag - while (root->pi[i] && strcmp(target, root->pi[i][0])) i++; // find target - return (const char **)((root->pi[i]) ? root->pi[i] + 1 : EZXML_NIL); -} - -// set an error string and return root -ezxml_t ezxml_err(ezxml_root_t root, char *s, const char *err, ...) -{ - va_list ap; - int line = 1; - char *t, fmt[EZXML_ERRL]; - - for (t = root->s; t < s; t++) if (*t == '\n') line++; - snprintf(fmt, EZXML_ERRL, "[error near line %d]: %s", line, err); - - va_start(ap, err); - vsnprintf(root->err, EZXML_ERRL, fmt, ap); - va_end(ap); - - return &root->xml; -} - -// Recursively decodes entity and character references and normalizes new lines -// ent is a null terminated array of alternating entity names and values. set t -// to '&' for general entity decoding, '%' for parameter entity decoding, 'c' -// for cdata sections, ' ' for attribute normalization, or '*' for non-cdata -// attribute normalization. Returns s, or if the decoded string is longer than -// s, returns a malloced string that must be freed. -char *ezxml_decode(char *s, char **ent, char t) -{ - char *e, *r = s, *m = s; - long b, c, d, l; - - for (; *s; s++) { // normalize line endings - while (*s == '\r') { - *(s++) = '\n'; - if (*s == '\n') memmove(s, (s + 1), strlen(s)); - } - } - - for (s = r; ; ) { - while (*s && *s != '&' && (*s != '%' || t != '%') && !isspace(*s)) s++; - - if (! *s) break; - else if (t != 'c' && ! strncmp(s, "&#", 2)) { // character reference - if (s[2] == 'x') c = strtol(s + 3, &e, 16); // base 16 - else c = strtol(s + 2, &e, 10); // base 10 - if (! c || *e != ';') { s++; continue; } // not a character ref - - if (c < 0x80) *(s++) = c; // US-ASCII subset - else { // multi-byte UTF-8 sequence - for (b = 0, d = c; d; d /= 2) b++; // number of bits in c - b = (b - 2) / 5; // number of bytes in payload - *(s++) = (0xFF << (7 - b)) | (c >> (6 * b)); // head - while (b) *(s++) = 0x80 | ((c >> (6 * --b)) & 0x3F); // payload - } - - memmove(s, strchr(s, ';') + 1, strlen(strchr(s, ';'))); - } - else if ((*s == '&' && (t == '&' || t == ' ' || t == '*')) || - (*s == '%' && t == '%')) { // entity reference - for (b = 0; ent[b] && strncmp(s + 1, ent[b], strlen(ent[b])); - b += 2); // find entity in entity list - - if (ent[b++]) { // found a match - if ((c = strlen(ent[b])) - 1 > (e = strchr(s, ';')) - s) { - l = (d = (s - r)) + c + strlen(e); // new length - r = (r == m) ? strcpy(malloc(l), r) : realloc(r, l); - e = strchr((s = r + d), ';'); // fix up pointers - } - - memmove(s + c, e + 1, strlen(e)); // shift rest of string - strncpy(s, ent[b], c); // copy in replacement text - } - else s++; // not a known entity - } - else if ((t == ' ' || t == '*') && isspace(*s)) *(s++) = ' '; - else s++; // no decoding needed - } - - if (t == '*') { // normalize spaces for non-cdata attributes - for (s = r; *s; s++) { - if ((l = strspn(s, " "))) memmove(s, s + l, strlen(s + l) + 1); - while (*s && *s != ' ') s++; - } - if (--s >= r && *s == ' ') *s = '\0'; // trim any trailing space - } - return r; -} - -// called when parser finds start of new tag -void ezxml_open_tag(ezxml_root_t root, char *name, char **attr) -{ - ezxml_t xml = root->cur; - - if (xml->name) xml = ezxml_add_child(xml, name, strlen(xml->txt)); - else xml->name = name; // first open tag - - xml->attr = attr; - root->cur = xml; // update tag insertion point -} - -// called when parser finds character content between open and closing tag -void ezxml_char_content(ezxml_root_t root, char *s, size_t len, char t) -{ - ezxml_t xml = root->cur; - char *m = s; - size_t l; - - if (! xml || ! xml->name || ! len) return; // sanity check - - s[len] = '\0'; // null terminate text (calling functions anticipate this) - len = strlen(s = ezxml_decode(s, root->ent, t)) + 1; - - if (! *(xml->txt)) xml->txt = s; // initial character content - else { // allocate our own memory and make a copy - xml->txt = (xml->flags & EZXML_TXTM) // allocate some space - ? realloc(xml->txt, (l = strlen(xml->txt)) + len) - : strcpy(malloc((l = strlen(xml->txt)) + len), xml->txt); - strcpy(xml->txt + l, s); // add new char content - if (s != m) free(s); // free s if it was malloced by ezxml_decode() - } - - if (xml->txt != m) ezxml_set_flag(xml, EZXML_TXTM); -} - -// called when parser finds closing tag -ezxml_t ezxml_close_tag(ezxml_root_t root, char *name, char *s) -{ - if (! root->cur || ! root->cur->name || strcmp(name, root->cur->name)) - return ezxml_err(root, s, "unexpected closing tag </%s>", name); - - root->cur = root->cur->parent; - return NULL; -} - -// checks for circular entity references, returns non-zero if no circular -// references are found, zero otherwise -int ezxml_ent_ok(char *name, char *s, char **ent) -{ - int i; - - for (; ; s++) { - while (*s && *s != '&') s++; // find next entity reference - if (! *s) return 1; - if (! strncmp(s + 1, name, strlen(name))) return 0; // circular ref. - for (i = 0; ent[i] && strncmp(ent[i], s + 1, strlen(ent[i])); i += 2); - if (ent[i] && ! ezxml_ent_ok(name, ent[i + 1], ent)) return 0; - } -} - -// called when the parser finds a processing instruction -void ezxml_proc_inst(ezxml_root_t root, char *s, size_t len) -{ - int i = 0, j = 1; - char *target = s; - - s[len] = '\0'; // null terminate instruction - if (*(s += strcspn(s, EZXML_WS))) { - *s = '\0'; // null terminate target - s += strspn(s + 1, EZXML_WS) + 1; // skip whitespace after target - } - - if (! strcmp(target, "xml")) { // <?xml ... ?> - if ((s = strstr(s, "standalone")) && ! strncmp(s + strspn(s + 10, - EZXML_WS "='\"") + 10, "yes", 3)) root->standalone = 1; - return; - } - - if (! root->pi[0]) *(root->pi = malloc(sizeof(char **))) = NULL; //first pi - - while (root->pi[i] && strcmp(target, root->pi[i][0])) i++; // find target - if (! root->pi[i]) { // new target - root->pi = realloc(root->pi, sizeof(char **) * (i + 2)); - root->pi[i] = malloc(sizeof(char *) * 3); - root->pi[i][0] = target; - root->pi[i][1] = (char *)(root->pi[i + 1] = NULL); // terminate pi list - root->pi[i][2] = strdup(""); // empty document position list - } - - while (root->pi[i][j]) j++; // find end of instruction list for this target - root->pi[i] = realloc(root->pi[i], sizeof(char *) * (j + 3)); - root->pi[i][j + 2] = realloc(root->pi[i][j + 1], j + 1); - strcpy(root->pi[i][j + 2] + j - 1, (root->xml.name) ? ">" : "<"); - root->pi[i][j + 1] = NULL; // null terminate pi list for this target - root->pi[i][j] = s; // set instruction -} - -// called when the parser finds an internal doctype subset -short ezxml_internal_dtd(ezxml_root_t root, char *s, size_t len) -{ - char q, *c, *t, *n = NULL, *v, **ent, **pe; - int i, j; - - pe = memcpy(malloc(sizeof(EZXML_NIL)), EZXML_NIL, sizeof(EZXML_NIL)); - - for (s[len] = '\0'; s; ) { - while (*s && *s != '<' && *s != '%') s++; // find next declaration - - if (! *s) break; - else if (! strncmp(s, "<!ENTITY", 8)) { // parse entity definitions - c = s += strspn(s + 8, EZXML_WS) + 8; // skip white space separator - n = s + strspn(s, EZXML_WS "%"); // find name - *(s = n + strcspn(n, EZXML_WS)) = ';'; // append ; to name - - v = s + strspn(s + 1, EZXML_WS) + 1; // find value - if ((q = *(v++)) != '"' && q != '\'') { // skip externals - s = strchr(s, '>'); - continue; - } - - for (i = 0, ent = (*c == '%') ? pe : root->ent; ent[i]; i++); - ent = realloc(ent, (i + 3) * sizeof(char *)); // space for next ent - if (*c == '%') pe = ent; - else root->ent = ent; - - *(++s) = '\0'; // null terminate name - if ((s = strchr(v, q))) *(s++) = '\0'; // null terminate value - ent[i + 1] = ezxml_decode(v, pe, '%'); // set value - ent[i + 2] = NULL; // null terminate entity list - if (! ezxml_ent_ok(n, ent[i + 1], ent)) { // circular reference - if (ent[i + 1] != v) free(ent[i + 1]); - ezxml_err(root, v, "circular entity declaration &%s", n); - break; - } - else ent[i] = n; // set entity name - } - else if (! strncmp(s, "<!ATTLIST", 9)) { // parse default attributes - t = s + strspn(s + 9, EZXML_WS) + 9; // skip whitespace separator - if (! *t) { ezxml_err(root, t, "unclosed <!ATTLIST"); break; } - if (*(s = t + strcspn(t, EZXML_WS ">")) == '>') continue; - else *s = '\0'; // null terminate tag name - for (i = 0; root->attr[i] && strcmp(n, root->attr[i][0]); i++); - - while (*(n = ++s + strspn(s, EZXML_WS)) && *n != '>') { - if (*(s = n + strcspn(n, EZXML_WS))) *s = '\0'; // attr name - else { ezxml_err(root, t, "malformed <!ATTLIST"); break; } - - s += strspn(s + 1, EZXML_WS) + 1; // find next token - c = (strncmp(s, "CDATA", 5)) ? "*" : " "; // is it cdata? - if (! strncmp(s, "NOTATION", 8)) - s += strspn(s + 8, EZXML_WS) + 8; - s = (*s == '(') ? strchr(s, ')') : s + strcspn(s, EZXML_WS); - if (! s) { ezxml_err(root, t, "malformed <!ATTLIST"); break; } - - s += strspn(s, EZXML_WS ")"); // skip white space separator - if (! strncmp(s, "#FIXED", 6)) - s += strspn(s + 6, EZXML_WS) + 6; - if (*s == '#') { // no default value - s += strcspn(s, EZXML_WS ">") - 1; - if (*c == ' ') continue; // cdata is default, nothing to do - v = NULL; - } - else if ((*s == '"' || *s == '\'') && // default value - (s = strchr(v = s + 1, *s))) *s = '\0'; - else { ezxml_err(root, t, "malformed <!ATTLIST"); break; } - - if (! root->attr[i]) { // new tag name - root->attr = (! i) ? malloc(2 * sizeof(char **)) - : realloc(root->attr, - (i + 2) * sizeof(char **)); - root->attr[i] = malloc(2 * sizeof(char *)); - root->attr[i][0] = t; // set tag name - root->attr[i][1] = (char *)(root->attr[i + 1] = NULL); - } - - for (j = 1; root->attr[i][j]; j += 3); // find end of list - root->attr[i] = realloc(root->attr[i], - (j + 4) * sizeof(char *)); - - root->attr[i][j + 3] = NULL; // null terminate list - root->attr[i][j + 2] = c; // is it cdata? - root->attr[i][j + 1] = (v) ? ezxml_decode(v, root->ent, *c) - : NULL; - root->attr[i][j] = n; // attribute name - } - } - else if (! strncmp(s, "<!--", 4)) s = strstr(s + 4, "-->"); // comments - else if (! strncmp(s, "<?", 2)) { // processing instructions - if ((s = strstr(c = s + 2, "?>"))) - ezxml_proc_inst(root, c, s++ - c); - } - else if (*s == '<') s = strchr(s, '>'); // skip other declarations - else if (*(s++) == '%' && ! root->standalone) break; - } - - free(pe); - return ! *root->err; -} - -// Converts a UTF-16 string to UTF-8. Returns a new string that must be freed -// or NULL if no conversion was needed. -char *ezxml_str2utf8(char **s, size_t *len) -{ - char *u; - size_t l = 0, sl, max = *len; - long c, d; - int b, be = (**s == '\xFE') ? 1 : (**s == '\xFF') ? 0 : -1; - - if (be == -1) return NULL; // not UTF-16 - - u = malloc(max); - for (sl = 2; sl < *len - 1; sl += 2) { - c = (be) ? (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF) //UTF-16BE - : (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF); //UTF-16LE - if (c >= 0xD800 && c <= 0xDFFF && (sl += 2) < *len - 1) { // high-half - d = (be) ? (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF) - : (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF); - c = (((c & 0x3FF) << 10) | (d & 0x3FF)) + 0x10000; - } - - while (l + 6 > max) u = realloc(u, max += EZXML_BUFSIZE); - if (c < 0x80) u[l++] = c; // US-ASCII subset - else { // multi-byte UTF-8 sequence - for (b = 0, d = c; d; d /= 2) b++; // bits in c - b = (b - 2) / 5; // bytes in payload - u[l++] = (0xFF << (7 - b)) | (c >> (6 * b)); // head - while (b) u[l++] = 0x80 | ((c >> (6 * --b)) & 0x3F); // payload - } - } - return *s = realloc(u, *len = l); -} - -// frees a tag attribute list -void ezxml_free_attr(char **attr) { - int i = 0; - char *m; - - if (! attr || attr == EZXML_NIL) return; // nothing to free - while (attr[i]) i += 2; // find end of attribute list - m = attr[i + 1]; // list of which names and values are malloced - for (i = 0; m[i]; i++) { - if (m[i] & EZXML_NAMEM) free(attr[i * 2]); - if (m[i] & EZXML_TXTM) free(attr[(i * 2) + 1]); - } - free(m); - free(attr); -} - -// parse the given xml string and return an ezxml structure -ezxml_t ezxml_parse_str(char *s, size_t len) -{ - ezxml_root_t root = (ezxml_root_t)ezxml_new(NULL); - char q, e, *d, **attr, **a = NULL; // initialize a to avoid compile warning - int l, i, j; - - root->m = s; - if (! len) return ezxml_err(root, NULL, "root tag missing"); - root->u = ezxml_str2utf8(&s, &len); // convert utf-16 to utf-8 - root->e = (root->s = s) + len; // record start and end of work area - - e = s[len - 1]; // save end char - s[len - 1] = '\0'; // turn end char into null terminator - - while (*s && *s != '<') s++; // find first tag - if (! *s) return ezxml_err(root, s, "root tag missing"); - - for (; ; ) { - attr = (char **)EZXML_NIL; - d = ++s; - - if (isalpha(*s) || *s == '_' || *s == ':' || *s < '\0') { // new tag - if (! root->cur) - return ezxml_err(root, d, "markup outside of root element"); - - s += strcspn(s, EZXML_WS "/>"); - while (isspace(*s)) *(s++) = '\0'; // null terminate tag name - - if (*s && *s != '/' && *s != '>') // find tag in default attr list - for (i = 0; (a = root->attr[i]) && strcmp(a[0], d); i++); - - for (l = 0; *s && *s != '/' && *s != '>'; l += 2) { // new attrib - attr = (l) ? realloc(attr, (l + 4) * sizeof(char *)) - : malloc(4 * sizeof(char *)); // allocate space - attr[l + 3] = (l) ? realloc(attr[l + 1], (l / 2) + 2) - : malloc(2); // mem for list of maloced vals - strcpy(attr[l + 3] + (l / 2), " "); // value is not malloced - attr[l + 2] = NULL; // null terminate list - attr[l + 1] = ""; // temporary attribute value - attr[l] = s; // set attribute name - - s += strcspn(s, EZXML_WS "=/>"); - if (*s == '=' || isspace(*s)) { - *(s++) = '\0'; // null terminate tag attribute name - q = *(s += strspn(s, EZXML_WS "=")); - if (q == '"' || q == '\'') { // attribute value - attr[l + 1] = ++s; - while (*s && *s != q) s++; - if (*s) *(s++) = '\0'; // null terminate attribute val - else { - ezxml_free_attr(attr); - return ezxml_err(root, d, "missing %c", q); - } - - for (j = 1; a && a[j] && strcmp(a[j], attr[l]); j +=3); - attr[l + 1] = ezxml_decode(attr[l + 1], root->ent, (a - && a[j]) ? *a[j + 2] : ' '); - if (attr[l + 1] < d || attr[l + 1] > s) - attr[l + 3][l / 2] = EZXML_TXTM; // value malloced - } - } - while (isspace(*s)) s++; - } - - if (*s == '/') { // self closing tag - *(s++) = '\0'; - if ((*s && *s != '>') || (! *s && e != '>')) { - if (l) ezxml_free_attr(attr); - return ezxml_err(root, d, "missing >"); - } - ezxml_open_tag(root, d, attr); - ezxml_close_tag(root, d, s); - } - else if ((q = *s) == '>' || (! *s && e == '>')) { // open tag - *s = '\0'; // temporarily null terminate tag name - ezxml_open_tag(root, d, attr); - *s = q; - } - else { - if (l) ezxml_free_attr(attr); - return ezxml_err(root, d, "missing >"); - } - } - else if (*s == '/') { // close tag - s += strcspn(d = s + 1, EZXML_WS ">") + 1; - if (! (q = *s) && e != '>') return ezxml_err(root, d, "missing >"); - *s = '\0'; // temporarily null terminate tag name - if (ezxml_close_tag(root, d, s)) return &root->xml; - if (isspace(*s = q)) s += strspn(s, EZXML_WS); - } - else if (! strncmp(s, "!--", 3)) { // xml comment - if (! (s = strstr(s + 3, "--")) || (*(s += 2) != '>' && *s) || - (! *s && e != '>')) return ezxml_err(root, d, "unclosed <!--"); - } - else if (! strncmp(s, "![CDATA[", 8)) { // cdata - if ((s = strstr(s, "]]>"))) - ezxml_char_content(root, d + 8, (s += 2) - d - 10, 'c'); - else return ezxml_err(root, d, "unclosed <![CDATA["); - } - else if (! strncmp(s, "!DOCTYPE", 8)) { // dtd - for (l = 0; *s && ((! l && *s != '>') || (l && (*s != ']' || - *(s + strspn(s + 1, EZXML_WS) + 1) != '>'))); - l = (*s == '[') ? 1 : l) s += strcspn(s + 1, "[]>") + 1; - if (! *s && e != '>') - return ezxml_err(root, d, "unclosed <!DOCTYPE"); - d = (l) ? strchr(d, '[') + 1 : d; - if (l && ! ezxml_internal_dtd(root, d, s++ - d)) return &root->xml; - } - else if (*s == '?') { // <?...?> processing instructions - do { s = strchr(s, '?'); } while (s && *(++s) && *s != '>'); - if (! s || (! *s && e != '>')) - return ezxml_err(root, d, "unclosed <?"); - else ezxml_proc_inst(root, d + 1, s - d - 2); - } - else return ezxml_err(root, d, "unexpected <"); - - if (! s || ! *s) break; - *s = '\0'; - d = ++s; - if (*s && *s != '<') { // tag character content - while (*s && *s != '<') s++; - if (*s) ezxml_char_content(root, d, s - d, '&'); - else break; - } - else if (! *s) break; - } - - if (! root->cur) return &root->xml; - else if (! root->cur->name) return ezxml_err(root, d, "root tag missing"); - else return ezxml_err(root, d, "unclosed tag <%s>", root->cur->name); -} - -// Wrapper for ezxml_parse_str() that accepts a file stream. Reads the entire -// stream into memory and then parses it. For xml files, use ezxml_parse_file() -// or ezxml_parse_fd() -ezxml_t ezxml_parse_fp(FILE *fp) -{ - ezxml_root_t root; - size_t l, len = 0; - char *s; - - if (! (s = malloc(EZXML_BUFSIZE))) return NULL; - do { - len += (l = fread((s + len), 1, EZXML_BUFSIZE, fp)); - if (l == EZXML_BUFSIZE) s = realloc(s, len + EZXML_BUFSIZE); - } while (s && l == EZXML_BUFSIZE); - - if (! s) return NULL; - root = (ezxml_root_t)ezxml_parse_str(s, len); - root->len = -1; // so we know to free s in ezxml_free() - return &root->xml; -} - -// A wrapper for ezxml_parse_str() that accepts a file descriptor. First -// attempts to mem map the file. Failing that, reads the file into memory. -// Returns NULL on failure. -ezxml_t ezxml_parse_fd(int fd) -{ - ezxml_root_t root; - struct stat st; - size_t l; - void *m; - - if (fd < 0) return NULL; - fstat(fd, &st); - -#ifndef EZXML_NOMMAP - l = (st.st_size + sysconf(_SC_PAGESIZE) - 1) & ~(sysconf(_SC_PAGESIZE) -1); - if ((m = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)) != - MAP_FAILED) { - madvise(m, l, MADV_SEQUENTIAL); // optimize for sequential access - root = (ezxml_root_t)ezxml_parse_str(m, st.st_size); - madvise(m, root->len = l, MADV_NORMAL); // put it back to normal - } - else { // mmap failed, read file into memory -#endif // EZXML_NOMMAP - l = read(fd, m = malloc(st.st_size), st.st_size); - root = (ezxml_root_t)ezxml_parse_str(m, l); - root->len = -1; // so we know to free s in ezxml_free() -#ifndef EZXML_NOMMAP - } -#endif // EZXML_NOMMAP - return &root->xml; -} - -// a wrapper for ezxml_parse_fd that accepts a file name -ezxml_t ezxml_parse_file(const char *file) -{ - int fd = open(file, O_RDONLY, 0); - ezxml_t xml = ezxml_parse_fd(fd); - - if (fd >= 0) close(fd); - return xml; -} - -// Encodes ampersand sequences appending the results to *dst, reallocating *dst -// if length excedes max. a is non-zero for attribute encoding. Returns *dst -char *ezxml_ampencode(const char *s, size_t len, char **dst, size_t *dlen, - size_t *max, short a) -{ - const char *e; - - for (e = s + len; s != e; s++) { - while (*dlen + 10 > *max) *dst = realloc(*dst, *max += EZXML_BUFSIZE); - - switch (*s) { - case '\0': return *dst; - case '&': *dlen += sprintf(*dst + *dlen, "&"); break; - case '<': *dlen += sprintf(*dst + *dlen, "<"); break; - case '>': *dlen += sprintf(*dst + *dlen, ">"); break; - case '"': *dlen += sprintf(*dst + *dlen, (a) ? """ : "\""); break; - case '\n': *dlen += sprintf(*dst + *dlen, (a) ? "
" : "\n"); break; - case '\t': *dlen += sprintf(*dst + *dlen, (a) ? "	" : "\t"); break; - case '\r': *dlen += sprintf(*dst + *dlen, "
"); break; - default: (*dst)[(*dlen)++] = *s; - } - } - return *dst; -} - -// Recursively converts each tag to xml appending it to *s. Reallocates *s if -// its length excedes max. start is the location of the previous tag in the -// parent tag's character content. Returns *s. -char *ezxml_toxml_r(ezxml_t xml, char **s, size_t *len, size_t *max, - size_t start, char ***attr) -{ - int i, j; - char *txt = (xml->parent) ? xml->parent->txt : ""; - size_t off = 0; - - // parent character content up to this tag - *s = ezxml_ampencode(txt + start, xml->off - start, s, len, max, 0); - - while (*len + strlen(xml->name) + 4 > *max) // reallocate s - *s = realloc(*s, *max += EZXML_BUFSIZE); - - *len += sprintf(*s + *len, "<%s", xml->name); // open tag - for (i = 0; xml->attr[i]; i += 2) { // tag attributes - if (ezxml_attr(xml, xml->attr[i]) != xml->attr[i + 1]) continue; - while (*len + strlen(xml->attr[i]) + 7 > *max) // reallocate s - *s = realloc(*s, *max += EZXML_BUFSIZE); - - *len += sprintf(*s + *len, " %s=\"", xml->attr[i]); - ezxml_ampencode(xml->attr[i + 1], -1, s, len, max, 1); - *len += sprintf(*s + *len, "\""); - } - - for (i = 0; attr[i] && strcmp(attr[i][0], xml->name); i++); - for (j = 1; attr[i] && attr[i][j]; j += 3) { // default attributes - if (! attr[i][j + 1] || ezxml_attr(xml, attr[i][j]) != attr[i][j + 1]) - continue; // skip duplicates and non-values - while (*len + strlen(attr[i][j]) + 7 > *max) // reallocate s - *s = realloc(*s, *max += EZXML_BUFSIZE); - - *len += sprintf(*s + *len, " %s=\"", attr[i][j]); - ezxml_ampencode(attr[i][j + 1], -1, s, len, max, 1); - *len += sprintf(*s + *len, "\""); - } - *len += sprintf(*s + *len, ">"); - - *s = (xml->child) ? ezxml_toxml_r(xml->child, s, len, max, 0, attr) //child - : ezxml_ampencode(xml->txt, -1, s, len, max, 0); //data - - while (*len + strlen(xml->name) + 4 > *max) // reallocate s - *s = realloc(*s, *max += EZXML_BUFSIZE); - - *len += sprintf(*s + *len, "</%s>", xml->name); // close tag - - while (txt[off] && off < xml->off) off++; // make sure off is within bounds - return (xml->ordered) ? ezxml_toxml_r(xml->ordered, s, len, max, off, attr) - : ezxml_ampencode(txt + off, -1, s, len, max, 0); -} - -// Converts an ezxml structure back to xml. Returns a string of xml data that -// must be freed. -char *ezxml_toxml(ezxml_t xml) -{ - ezxml_t p = (xml) ? xml->parent : NULL, o = (xml) ? xml->ordered : NULL; - ezxml_root_t root = (ezxml_root_t)xml; - size_t len = 0, max = EZXML_BUFSIZE; - char *s = strcpy(malloc(max), ""), *t, *n; - int i, j, k; - - if (! xml || ! xml->name) return realloc(s, len + 1); - while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag - - for (i = 0; ! p && root->pi[i]; i++) { // pre-root processing instructions - for (k = 2; root->pi[i][k - 1]; k++); - for (j = 1; (n = root->pi[i][j]); j++) { - if (root->pi[i][k][j - 1] == '>') continue; // not pre-root - while (len + strlen(t = root->pi[i][0]) + strlen(n) + 7 > max) - s = realloc(s, max += EZXML_BUFSIZE); - len += sprintf(s + len, "<?%s%s%s?>\n", t, *n ? " " : "", n); - } - } - - xml->parent = xml->ordered = NULL; - s = ezxml_toxml_r(xml, &s, &len, &max, 0, root->attr); - xml->parent = p; - xml->ordered = o; - - for (i = 0; ! p && root->pi[i]; i++) { // post-root processing instructions - for (k = 2; root->pi[i][k - 1]; k++); - for (j = 1; (n = root->pi[i][j]); j++) { - if (root->pi[i][k][j - 1] == '<') continue; // not post-root - while (len + strlen(t = root->pi[i][0]) + strlen(n) + 7 > max) - s = realloc(s, max += EZXML_BUFSIZE); - len += sprintf(s + len, "\n<?%s%s%s?>", t, *n ? " " : "", n); - } - } - return realloc(s, len + 1); -} - -// free the memory allocated for the ezxml structure -void ezxml_free(ezxml_t xml) -{ - ezxml_root_t root = (ezxml_root_t)xml; - int i, j; - char **a, *s; - - if (! xml) return; - ezxml_free(xml->child); - ezxml_free(xml->ordered); - - if (! xml->parent) { // free root tag allocations - for (i = 10; root->ent[i]; i += 2) // 0 - 9 are default entites (<>&"') - if ((s = root->ent[i + 1]) < root->s || s > root->e) free(s); - free(root->ent); // free list of general entities - - for (i = 0; (a = root->attr[i]); i++) { - for (j = 1; a[j++]; j += 2) // free malloced attribute values - if (a[j] && (a[j] < root->s || a[j] > root->e)) free(a[j]); - free(a); - } - if (root->attr[0]) free(root->attr); // free default attribute list - - for (i = 0; root->pi[i]; i++) { - for (j = 1; root->pi[i][j]; j++); - free(root->pi[i][j + 1]); - free(root->pi[i]); - } - if (root->pi[0]) free(root->pi); // free processing instructions - - if (root->len == -1) free(root->m); // malloced xml data -#ifndef EZXML_NOMMAP - else if (root->len) munmap(root->m, root->len); // mem mapped xml data -#endif // EZXML_NOMMAP - if (root->u) free(root->u); // utf8 conversion - } - - ezxml_free_attr(xml->attr); // tag attributes - if ((xml->flags & EZXML_TXTM)) free(xml->txt); // character content - if ((xml->flags & EZXML_NAMEM)) free(xml->name); // tag name - free(xml); -} - -// return parser error message or empty string if none -const char *ezxml_error(ezxml_t xml) -{ - while (xml && xml->parent) xml = xml->parent; // find root tag - return (xml) ? ((ezxml_root_t)xml)->err : ""; -} - -// returns a new empty ezxml structure with the given root tag name -ezxml_t ezxml_new(const char *name) -{ - static char *ent[] = { "lt;", "<", "gt;", ">", "quot;", """, - "apos;", "'", "amp;", "&", NULL }; - ezxml_root_t root = (ezxml_root_t)memset(malloc(sizeof(struct ezxml_root)), - '\0', sizeof(struct ezxml_root)); - root->xml.name = (char *)name; - root->cur = &root->xml; - strcpy(root->err, root->xml.txt = ""); - root->ent = memcpy(malloc(sizeof(ent)), ent, sizeof(ent)); - root->attr = root->pi = (char ***)(root->xml.attr = EZXML_NIL); - return &root->xml; -} - -// inserts an existing tag into an ezxml structure -ezxml_t ezxml_insert(ezxml_t xml, ezxml_t dest, size_t off) -{ - ezxml_t cur, prev, head; - - xml->next = xml->sibling = xml->ordered = NULL; - xml->off = off; - xml->parent = dest; - - if ((head = dest->child)) { // already have sub tags - if (head->off <= off) { // not first subtag - for (cur = head; cur->ordered && cur->ordered->off <= off; - cur = cur->ordered); - xml->ordered = cur->ordered; - cur->ordered = xml; - } - else { // first subtag - xml->ordered = head; - dest->child = xml; - } - - for (cur = head, prev = NULL; cur && strcmp(cur->name, xml->name); - prev = cur, cur = cur->sibling); // find tag type - if (cur && cur->off <= off) { // not first of type - while (cur->next && cur->next->off <= off) cur = cur->next; - xml->next = cur->next; - cur->next = xml; - } - else { // first tag of this type - if (prev && cur) prev->sibling = cur->sibling; // remove old first - xml->next = cur; // old first tag is now next - for (cur = head, prev = NULL; cur && cur->off <= off; - prev = cur, cur = cur->sibling); // new sibling insert point - xml->sibling = cur; - if (prev) prev->sibling = xml; - } - } - else dest->child = xml; // only sub tag - - return xml; -} - -// Adds a child tag. off is the offset of the child tag relative to the start -// of the parent tag's character content. Returns the child tag. -ezxml_t ezxml_add_child(ezxml_t xml, const char *name, size_t off) -{ - ezxml_t child; - - if (! xml) return NULL; - child = (ezxml_t)memset(malloc(sizeof(struct ezxml)), '\0', - sizeof(struct ezxml)); - child->name = (char *)name; - child->attr = EZXML_NIL; - child->txt = ""; - - return ezxml_insert(child, xml, off); -} - -// sets the character content for the given tag and returns the tag -ezxml_t ezxml_set_txt(ezxml_t xml, const char *txt) -{ - if (! xml) return NULL; - if (xml->flags & EZXML_TXTM) free(xml->txt); // existing txt was malloced - xml->flags &= ~EZXML_TXTM; - xml->txt = (char *)txt; - return xml; -} - -// Sets the given tag attribute or adds a new attribute if not found. A value -// of NULL will remove the specified attribute. Returns the tag given. -ezxml_t ezxml_set_attr(ezxml_t xml, const char *name, const char *value) -{ - int l = 0, c; - - if (! xml) return NULL; - while (xml->attr[l] && strcmp(xml->attr[l], name)) l += 2; - if (! xml->attr[l]) { // not found, add as new attribute - if (! value) return xml; // nothing to do - if (xml->attr == EZXML_NIL) { // first attribute - xml->attr = malloc(4 * sizeof(char *)); - xml->attr[1] = strdup(""); // empty list of malloced names/vals - } - else xml->attr = realloc(xml->attr, (l + 4) * sizeof(char *)); - - xml->attr[l] = (char *)name; // set attribute name - xml->attr[l + 2] = NULL; // null terminate attribute list - xml->attr[l + 3] = realloc(xml->attr[l + 1], - (c = strlen(xml->attr[l + 1])) + 2); - strcpy(xml->attr[l + 3] + c, " "); // set name/value as not malloced - if (xml->flags & EZXML_DUP) xml->attr[l + 3][c] = EZXML_NAMEM; - } - else if (xml->flags & EZXML_DUP) free((char *)name); // name was strduped - - for (c = l; xml->attr[c]; c += 2); // find end of attribute list - if (xml->attr[c + 1][l / 2] & EZXML_TXTM) free(xml->attr[l + 1]); //old val - if (xml->flags & EZXML_DUP) xml->attr[c + 1][l / 2] |= EZXML_TXTM; - else xml->attr[c + 1][l / 2] &= ~EZXML_TXTM; - - if (value) xml->attr[l + 1] = (char *)value; // set attribute value - else { // remove attribute - if (xml->attr[c + 1][l / 2] & EZXML_NAMEM) free(xml->attr[l]); - memmove(xml->attr + l, xml->attr + l + 2, (c - l + 2) * sizeof(char*)); - xml->attr = realloc(xml->attr, (c + 2) * sizeof(char *)); - memmove(xml->attr[c + 1] + (l / 2), xml->attr[c + 1] + (l / 2) + 1, - (c / 2) - (l / 2)); // fix list of which name/vals are malloced - } - xml->flags &= ~EZXML_DUP; // clear strdup() flag - return xml; -} - -// sets a flag for the given tag and returns the tag -ezxml_t ezxml_set_flag(ezxml_t xml, short flag) -{ - if (xml) xml->flags |= flag; - return xml; -} - -// removes a tag along with its subtags without freeing its memory -ezxml_t ezxml_cut(ezxml_t xml) -{ - ezxml_t cur; - - if (! xml) return NULL; // nothing to do - if (xml->next) xml->next->sibling = xml->sibling; // patch sibling list - - if (xml->parent) { // not root tag - cur = xml->parent->child; // find head of subtag list - if (cur == xml) xml->parent->child = xml->ordered; // first subtag - else { // not first subtag - while (cur->ordered != xml) cur = cur->ordered; - cur->ordered = cur->ordered->ordered; // patch ordered list - - cur = xml->parent->child; // go back to head of subtag list - if (strcmp(cur->name, xml->name)) { // not in first sibling list - while (strcmp(cur->sibling->name, xml->name)) - cur = cur->sibling; - if (cur->sibling == xml) { // first of a sibling list - cur->sibling = (xml->next) ? xml->next - : cur->sibling->sibling; - } - else cur = cur->sibling; // not first of a sibling list - } - - while (cur->next && cur->next != xml) cur = cur->next; - if (cur->next) cur->next = cur->next->next; // patch next list - } - } - xml->ordered = xml->sibling = xml->next = NULL; - return xml; -} - -#ifdef EZXML_TEST // test harness -int main(int argc, char **argv) -{ - ezxml_t xml; - char *s; - int i; - - if (argc != 2) return fprintf(stderr, "usage: %s xmlfile\n", argv[0]); - - xml = ezxml_parse_file(argv[1]); - printf("%s\n", (s = ezxml_toxml(xml))); - free(s); - i = fprintf(stderr, "%s", ezxml_error(xml)); - ezxml_free(xml); - return (i) ? 1 : 0; -} -#endif // EZXML_TEST diff --git a/3rdparty/ezxml/ezxml.h b/3rdparty/ezxml/ezxml.h deleted file mode 100644 index 3e02078..0000000 --- a/3rdparty/ezxml/ezxml.h +++ /dev/null @@ -1,167 +0,0 @@ -/* ezxml.h - * - * Copyright 2004-2006 Aaron Voisine <aaron@voisine.org> - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _EZXML_H -#define _EZXML_H - -#include <stdlib.h> -#include <stdio.h> -#include <stdarg.h> -#include <fcntl.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#define EZXML_BUFSIZE 1024 // size of internal memory buffers -#define EZXML_NAMEM 0x80 // name is malloced -#define EZXML_TXTM 0x40 // txt is malloced -#define EZXML_DUP 0x20 // attribute name and value are strduped - -typedef struct ezxml *ezxml_t; -struct ezxml { - char *name; // tag name - char **attr; // tag attributes { name, value, name, value, ... NULL } - char *txt; // tag character content, empty string if none - size_t off; // tag offset from start of parent tag character content - ezxml_t next; // next tag with same name in this section at this depth - ezxml_t sibling; // next tag with different name in same section and depth - ezxml_t ordered; // next tag, same section and depth, in original order - ezxml_t child; // head of sub tag list, NULL if none - ezxml_t parent; // parent tag, NULL if current tag is root tag - short flags; // additional information -}; - -// Given a string of xml data and its length, parses it and creates an ezxml -// structure. For efficiency, modifies the data by adding null terminators -// and decoding ampersand sequences. If you don't want this, copy the data and -// pass in the copy. Returns NULL on failure. -ezxml_t ezxml_parse_str(char *s, size_t len); - -// A wrapper for ezxml_parse_str() that accepts a file descriptor. First -// attempts to mem map the file. Failing that, reads the file into memory. -// Returns NULL on failure. -ezxml_t ezxml_parse_fd(int fd); - -// a wrapper for ezxml_parse_fd() that accepts a file name -ezxml_t ezxml_parse_file(const char *file); - -// Wrapper for ezxml_parse_str() that accepts a file stream. Reads the entire -// stream into memory and then parses it. For xml files, use ezxml_parse_file() -// or ezxml_parse_fd() -ezxml_t ezxml_parse_fp(FILE *fp); - -// returns the first child tag (one level deeper) with the given name or NULL -// if not found -ezxml_t ezxml_child(ezxml_t xml, const char *name); - -// returns the next tag of the same name in the same section and depth or NULL -// if not found -#define ezxml_next(xml) ((xml) ? xml->next : NULL) - -// Returns the Nth tag with the same name in the same section at the same depth -// or NULL if not found. An index of 0 returns the tag given. -ezxml_t ezxml_idx(ezxml_t xml, int idx); - -// returns the name of the given tag -#define ezxml_name(xml) ((xml) ? xml->name : NULL) - -// returns the given tag's character content or empty string if none -#define ezxml_txt(xml) ((xml) ? xml->txt : "") - -// returns the value of the requested tag attribute, or NULL if not found -const char *ezxml_attr(ezxml_t xml, const char *attr); - -// Traverses the ezxml sturcture to retrieve a specific subtag. Takes a -// variable length list of tag names and indexes. The argument list must be -// terminated by either an index of -1 or an empty string tag name. Example: -// title = ezxml_get(library, "shelf", 0, "book", 2, "title", -1); -// This retrieves the title of the 3rd book on the 1st shelf of library. -// Returns NULL if not found. -ezxml_t ezxml_get(ezxml_t xml, ...); - -// Converts an ezxml structure back to xml. Returns a string of xml data that -// must be freed. -char *ezxml_toxml(ezxml_t xml); - -// returns a NULL terminated array of processing instructions for the given -// target -const char **ezxml_pi(ezxml_t xml, const char *target); - -// frees the memory allocated for an ezxml structure -void ezxml_free(ezxml_t xml); - -// returns parser error message or empty string if none -const char *ezxml_error(ezxml_t xml); - -// returns a new empty ezxml structure with the given root tag name -ezxml_t ezxml_new(const char *name); - -// wrapper for ezxml_new() that strdup()s name -#define ezxml_new_d(name) ezxml_set_flag(ezxml_new(strdup(name)), EZXML_NAMEM) - -// Adds a child tag. off is the offset of the child tag relative to the start -// of the parent tag's character content. Returns the child tag. -ezxml_t ezxml_add_child(ezxml_t xml, const char *name, size_t off); - -// wrapper for ezxml_add_child() that strdup()s name -#define ezxml_add_child_d(xml, name, off) \ - ezxml_set_flag(ezxml_add_child(xml, strdup(name), off), EZXML_NAMEM) - -// sets the character content for the given tag and returns the tag -ezxml_t ezxml_set_txt(ezxml_t xml, const char *txt); - -// wrapper for ezxml_set_txt() that strdup()s txt -#define ezxml_set_txt_d(xml, txt) \ - ezxml_set_flag(ezxml_set_txt(xml, strdup(txt)), EZXML_TXTM) - -// Sets the given tag attribute or adds a new attribute if not found. A value -// of NULL will remove the specified attribute. Returns the tag given. -ezxml_t ezxml_set_attr(ezxml_t xml, const char *name, const char *value); - -// Wrapper for ezxml_set_attr() that strdup()s name/value. Value cannot be NULL -#define ezxml_set_attr_d(xml, name, value) \ - ezxml_set_attr(ezxml_set_flag(xml, EZXML_DUP), strdup(name), strdup(value)) - -// sets a flag for the given tag and returns the tag -ezxml_t ezxml_set_flag(ezxml_t xml, short flag); - -// removes a tag along with its subtags without freeing its memory -ezxml_t ezxml_cut(ezxml_t xml); - -// inserts an existing tag into an ezxml structure -ezxml_t ezxml_insert(ezxml_t xml, ezxml_t dest, size_t off); - -// Moves an existing tag to become a subtag of dest at the given offset from -// the start of dest's character content. Returns the moved tag. -#define ezxml_move(xml, dest, off) ezxml_insert(ezxml_cut(xml), dest, off) - -// removes a tag along with all its subtags -#define ezxml_remove(xml) ezxml_free(ezxml_cut(xml)) - -#ifdef __cplusplus -} -#endif - -#endif // _EZXML_H diff --git a/3rdparty/stb_ds.h b/3rdparty/stb_ds.h deleted file mode 100644 index e84c82d..0000000 --- a/3rdparty/stb_ds.h +++ /dev/null @@ -1,1895 +0,0 @@ -/* stb_ds.h - v0.67 - public domain data structures - Sean Barrett 2019 - - This is a single-header-file library that provides easy-to-use - dynamic arrays and hash tables for C (also works in C++). - - For a gentle introduction: - http://nothings.org/stb_ds - - To use this library, do this in *one* C or C++ file: - #define STB_DS_IMPLEMENTATION - #include "stb_ds.h" - -TABLE OF CONTENTS - - Table of Contents - Compile-time options - License - Documentation - Notes - Notes - Dynamic arrays - Notes - Hash maps - Credits - -COMPILE-TIME OPTIONS - - #define STBDS_NO_SHORT_NAMES - - This flag needs to be set globally. - - By default stb_ds exposes shorter function names that are not qualified - with the "stbds_" prefix. If these names conflict with the names in your - code, define this flag. - - #define STBDS_SIPHASH_2_4 - - This flag only needs to be set in the file containing #define STB_DS_IMPLEMENTATION. - - By default stb_ds.h hashes using a weaker variant of SipHash and a custom hash for - 4- and 8-byte keys. On 64-bit platforms, you can define the above flag to force - stb_ds.h to use specification-compliant SipHash-2-4 for all keys. Doing so makes - hash table insertion about 20% slower on 4- and 8-byte keys, 5% slower on - 64-byte keys, and 10% slower on 256-byte keys on my test computer. - - #define STBDS_REALLOC(context,ptr,size) better_realloc - #define STBDS_FREE(context,ptr) better_free - - These defines only need to be set in the file containing #define STB_DS_IMPLEMENTATION. - - By default stb_ds uses stdlib realloc() and free() for memory management. You can - substitute your own functions instead by defining these symbols. You must either - define both, or neither. Note that at the moment, 'context' will always be NULL. - @TODO add an array/hash initialization function that takes a memory context pointer. - - #define STBDS_UNIT_TESTS - - Defines a function stbds_unit_tests() that checks the functioning of the data structures. - - Note that on older versions of gcc (e.g. 5.x.x) you may need to build with '-std=c++0x' - (or equivalentally '-std=c++11') when using anonymous structures as seen on the web - page or in STBDS_UNIT_TESTS. - -LICENSE - - Placed in the public domain and also MIT licensed. - See end of file for detailed license information. - -DOCUMENTATION - - Dynamic Arrays - - Non-function interface: - - Declare an empty dynamic array of type T - T* foo = NULL; - - Access the i'th item of a dynamic array 'foo' of type T, T* foo: - foo[i] - - Functions (actually macros) - - arrfree: - void arrfree(T*); - Frees the array. - - arrlen: - ptrdiff_t arrlen(T*); - Returns the number of elements in the array. - - arrlenu: - size_t arrlenu(T*); - Returns the number of elements in the array as an unsigned type. - - arrpop: - T arrpop(T* a) - Removes the final element of the array and returns it. - - arrput: - T arrput(T* a, T b); - Appends the item b to the end of array a. Returns b. - - arrins: - T arrins(T* a, int p, T b); - Inserts the item b into the middle of array a, into a[p], - moving the rest of the array over. Returns b. - - arrinsn: - void arrinsn(T* a, int p, int n); - Inserts n uninitialized items into array a starting at a[p], - moving the rest of the array over. - - arraddnptr: - T* arraddnptr(T* a, int n) - Appends n uninitialized items onto array at the end. - Returns a pointer to the first uninitialized item added. - - arraddnindex: - size_t arraddnindex(T* a, int n) - Appends n uninitialized items onto array at the end. - Returns the index of the first uninitialized item added. - - arrdel: - void arrdel(T* a, int p); - Deletes the element at a[p], moving the rest of the array over. - - arrdeln: - void arrdeln(T* a, int p, int n); - Deletes n elements starting at a[p], moving the rest of the array over. - - arrdelswap: - void arrdelswap(T* a, int p); - Deletes the element at a[p], replacing it with the element from - the end of the array. O(1) performance. - - arrsetlen: - void arrsetlen(T* a, int n); - Changes the length of the array to n. Allocates uninitialized - slots at the end if necessary. - - arrsetcap: - size_t arrsetcap(T* a, int n); - Sets the length of allocated storage to at least n. It will not - change the length of the array. - - arrcap: - size_t arrcap(T* a); - Returns the number of total elements the array can contain without - needing to be reallocated. - - Hash maps & String hash maps - - Given T is a structure type: struct { TK key; TV value; }. Note that some - functions do not require TV value and can have other fields. For string - hash maps, TK must be 'char *'. - - Special interface: - - stbds_rand_seed: - void stbds_rand_seed(size_t seed); - For security against adversarially chosen data, you should seed the - library with a strong random number. Or at least seed it with time(). - - stbds_hash_string: - size_t stbds_hash_string(char *str, size_t seed); - Returns a hash value for a string. - - stbds_hash_bytes: - size_t stbds_hash_bytes(void *p, size_t len, size_t seed); - These functions hash an arbitrary number of bytes. The function - uses a custom hash for 4- and 8-byte data, and a weakened version - of SipHash for everything else. On 64-bit platforms you can get - specification-compliant SipHash-2-4 on all data by defining - STBDS_SIPHASH_2_4, at a significant cost in speed. - - Non-function interface: - - Declare an empty hash map of type T - T* foo = NULL; - - Access the i'th entry in a hash table T* foo: - foo[i] - - Function interface (actually macros): - - hmfree - shfree - void hmfree(T*); - void shfree(T*); - Frees the hashmap and sets the pointer to NULL. - - hmlen - shlen - ptrdiff_t hmlen(T*) - ptrdiff_t shlen(T*) - Returns the number of elements in the hashmap. - - hmlenu - shlenu - size_t hmlenu(T*) - size_t shlenu(T*) - Returns the number of elements in the hashmap. - - hmgeti - shgeti - hmgeti_ts - ptrdiff_t hmgeti(T*, TK key) - ptrdiff_t shgeti(T*, char* key) - ptrdiff_t hmgeti_ts(T*, TK key, ptrdiff_t tempvar) - Returns the index in the hashmap which has the key 'key', or -1 - if the key is not present. - - hmget - hmget_ts - shget - TV hmget(T*, TK key) - TV shget(T*, char* key) - TV hmget_ts(T*, TK key, ptrdiff_t tempvar) - Returns the value corresponding to 'key' in the hashmap. - The structure must have a 'value' field - - hmgets - shgets - T hmgets(T*, TK key) - T shgets(T*, char* key) - Returns the structure corresponding to 'key' in the hashmap. - - hmgetp - shgetp - hmgetp_ts - hmgetp_null - shgetp_null - T* hmgetp(T*, TK key) - T* shgetp(T*, char* key) - T* hmgetp_ts(T*, TK key, ptrdiff_t tempvar) - T* hmgetp_null(T*, TK key) - T* shgetp_null(T*, char *key) - Returns a pointer to the structure corresponding to 'key' in - the hashmap. Functions ending in "_null" return NULL if the key - is not present in the hashmap; the others return a pointer to a - structure holding the default value (but not the searched-for key). - - hmdefault - shdefault - TV hmdefault(T*, TV value) - TV shdefault(T*, TV value) - Sets the default value for the hashmap, the value which will be - returned by hmget/shget if the key is not present. - - hmdefaults - shdefaults - TV hmdefaults(T*, T item) - TV shdefaults(T*, T item) - Sets the default struct for the hashmap, the contents which will be - returned by hmgets/shgets if the key is not present. - - hmput - shput - TV hmput(T*, TK key, TV value) - TV shput(T*, char* key, TV value) - Inserts a <key,value> pair into the hashmap. If the key is already - present in the hashmap, updates its value. - - hmputs - shputs - T hmputs(T*, T item) - T shputs(T*, T item) - Inserts a struct with T.key into the hashmap. If the struct is already - present in the hashmap, updates it. - - hmdel - shdel - int hmdel(T*, TK key) - int shdel(T*, char* key) - If 'key' is in the hashmap, deletes its entry and returns 1. - Otherwise returns 0. - - Function interface (actually macros) for strings only: - - sh_new_strdup - void sh_new_strdup(T*); - Overwrites the existing pointer with a newly allocated - string hashmap which will automatically allocate and free - each string key using realloc/free - - sh_new_arena - void sh_new_arena(T*); - Overwrites the existing pointer with a newly allocated - string hashmap which will automatically allocate each string - key to a string arena. Every string key ever used by this - hash table remains in the arena until the arena is freed. - Additionally, any key which is deleted and reinserted will - be allocated multiple times in the string arena. - -NOTES - - * These data structures are realloc'd when they grow, and the macro - "functions" write to the provided pointer. This means: (a) the pointer - must be an lvalue, and (b) the pointer to the data structure is not - stable, and you must maintain it the same as you would a realloc'd - pointer. For example, if you pass a pointer to a dynamic array to a - function which updates it, the function must return back the new - pointer to the caller. This is the price of trying to do this in C. - - * The following are the only functions that are thread-safe on a single data - structure, i.e. can be run in multiple threads simultaneously on the same - data structure - hmlen shlen - hmlenu shlenu - hmget_ts shget_ts - hmgeti_ts shgeti_ts - hmgets_ts shgets_ts - - * You iterate over the contents of a dynamic array and a hashmap in exactly - the same way, using arrlen/hmlen/shlen: - - for (i=0; i < arrlen(foo); ++i) - ... foo[i] ... - - * All operations except arrins/arrdel are O(1) amortized, but individual - operations can be slow, so these data structures may not be suitable - for real time use. Dynamic arrays double in capacity as needed, so - elements are copied an average of once. Hash tables double/halve - their size as needed, with appropriate hysteresis to maintain O(1) - performance. - -NOTES - DYNAMIC ARRAY - - * If you know how long a dynamic array is going to be in advance, you can avoid - extra memory allocations by using arrsetlen to allocate it to that length in - advance and use foo[n] while filling it out, or arrsetcap to allocate the memory - for that length and use arrput/arrpush as normal. - - * Unlike some other versions of the dynamic array, this version should - be safe to use with strict-aliasing optimizations. - -NOTES - HASH MAP - - * For compilers other than GCC and clang (e.g. Visual Studio), for hmput/hmget/hmdel - and variants, the key must be an lvalue (so the macro can take the address of it). - Extensions are used that eliminate this requirement if you're using C99 and later - in GCC or clang, or if you're using C++ in GCC. But note that this can make your - code less portable. - - * To test for presence of a key in a hashmap, just do 'hmgeti(foo,key) >= 0'. - - * The iteration order of your data in the hashmap is determined solely by the - order of insertions and deletions. In particular, if you never delete, new - keys are always added at the end of the array. This will be consistent - across all platforms and versions of the library. However, you should not - attempt to serialize the internal hash table, as the hash is not consistent - between different platforms, and may change with future versions of the library. - - * Use sh_new_arena() for string hashmaps that you never delete from. Initialize - with NULL if you're managing the memory for your strings, or your strings are - never freed (at least until the hashmap is freed). Otherwise, use sh_new_strdup(). - @TODO: make an arena variant that garbage collects the strings with a trivial - copy collector into a new arena whenever the table shrinks / rebuilds. Since - current arena recommendation is to only use arena if it never deletes, then - this can just replace current arena implementation. - - * If adversarial input is a serious concern and you're on a 64-bit platform, - enable STBDS_SIPHASH_2_4 (see the 'Compile-time options' section), and pass - a strong random number to stbds_rand_seed. - - * The default value for the hash table is stored in foo[-1], so if you - use code like 'hmget(T,k)->value = 5' you can accidentally overwrite - the value stored by hmdefault if 'k' is not present. - -CREDITS - - Sean Barrett -- library, idea for dynamic array API/implementation - Per Vognsen -- idea for hash table API/implementation - Rafael Sachetto -- arrpop() - github:HeroicKatora -- arraddn() reworking - - Bugfixes: - Andy Durdin - Shane Liesegang - Vinh Truong - Andreas Molzer - github:hashitaku - github:srdjanstipic - Macoy Madson - Andreas Vennstrom - Tobias Mansfield-Williams -*/ - -#ifdef STBDS_UNIT_TESTS -#define _CRT_SECURE_NO_WARNINGS -#endif - -#ifndef INCLUDE_STB_DS_H -#define INCLUDE_STB_DS_H - -#include <stddef.h> -#include <string.h> - -#ifndef STBDS_NO_SHORT_NAMES -#define arrlen stbds_arrlen -#define arrlenu stbds_arrlenu -#define arrput stbds_arrput -#define arrpush stbds_arrput -#define arrpop stbds_arrpop -#define arrfree stbds_arrfree -#define arraddn stbds_arraddn // deprecated, use one of the following instead: -#define arraddnptr stbds_arraddnptr -#define arraddnindex stbds_arraddnindex -#define arrsetlen stbds_arrsetlen -#define arrlast stbds_arrlast -#define arrins stbds_arrins -#define arrinsn stbds_arrinsn -#define arrdel stbds_arrdel -#define arrdeln stbds_arrdeln -#define arrdelswap stbds_arrdelswap -#define arrcap stbds_arrcap -#define arrsetcap stbds_arrsetcap - -#define hmput stbds_hmput -#define hmputs stbds_hmputs -#define hmget stbds_hmget -#define hmget_ts stbds_hmget_ts -#define hmgets stbds_hmgets -#define hmgetp stbds_hmgetp -#define hmgetp_ts stbds_hmgetp_ts -#define hmgetp_null stbds_hmgetp_null -#define hmgeti stbds_hmgeti -#define hmgeti_ts stbds_hmgeti_ts -#define hmdel stbds_hmdel -#define hmlen stbds_hmlen -#define hmlenu stbds_hmlenu -#define hmfree stbds_hmfree -#define hmdefault stbds_hmdefault -#define hmdefaults stbds_hmdefaults - -#define shput stbds_shput -#define shputi stbds_shputi -#define shputs stbds_shputs -#define shget stbds_shget -#define shgeti stbds_shgeti -#define shgets stbds_shgets -#define shgetp stbds_shgetp -#define shgetp_null stbds_shgetp_null -#define shdel stbds_shdel -#define shlen stbds_shlen -#define shlenu stbds_shlenu -#define shfree stbds_shfree -#define shdefault stbds_shdefault -#define shdefaults stbds_shdefaults -#define sh_new_arena stbds_sh_new_arena -#define sh_new_strdup stbds_sh_new_strdup - -#define stralloc stbds_stralloc -#define strreset stbds_strreset -#endif - -#if defined(STBDS_REALLOC) && !defined(STBDS_FREE) || !defined(STBDS_REALLOC) && defined(STBDS_FREE) -#error "You must define both STBDS_REALLOC and STBDS_FREE, or neither." -#endif -#if !defined(STBDS_REALLOC) && !defined(STBDS_FREE) -#include <stdlib.h> -#define STBDS_REALLOC(c,p,s) realloc(p,s) -#define STBDS_FREE(c,p) free(p) -#endif - -#ifdef _MSC_VER -#define STBDS_NOTUSED(v) (void)(v) -#else -#define STBDS_NOTUSED(v) (void)sizeof(v) -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// for security against attackers, seed the library with a random number, at least time() but stronger is better -extern void stbds_rand_seed(size_t seed); - -// these are the hash functions used internally if you want to test them or use them for other purposes -extern size_t stbds_hash_bytes(void *p, size_t len, size_t seed); -extern size_t stbds_hash_string(char *str, size_t seed); - -// this is a simple string arena allocator, initialize with e.g. 'stbds_string_arena my_arena={0}'. -typedef struct stbds_string_arena stbds_string_arena; -extern char * stbds_stralloc(stbds_string_arena *a, char *str); -extern void stbds_strreset(stbds_string_arena *a); - -// have to #define STBDS_UNIT_TESTS to call this -extern void stbds_unit_tests(void); - -/////////////// -// -// Everything below here is implementation details -// - -extern void * stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap); -extern void stbds_arrfreef(void *a); -extern void stbds_hmfree_func(void *p, size_t elemsize); -extern void * stbds_hmget_key(void *a, size_t elemsize, void *key, size_t keysize, int mode); -extern void * stbds_hmget_key_ts(void *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode); -extern void * stbds_hmput_default(void *a, size_t elemsize); -extern void * stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int mode); -extern void * stbds_hmdel_key(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode); -extern void * stbds_shmode_func(size_t elemsize, int mode); - -#ifdef __cplusplus -} -#endif - -#if defined(__GNUC__) || defined(__clang__) -#define STBDS_HAS_TYPEOF -#ifdef __cplusplus -//#define STBDS_HAS_LITERAL_ARRAY // this is currently broken for clang -#endif -#endif - -#if !defined(__cplusplus) -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -#define STBDS_HAS_LITERAL_ARRAY -#endif -#endif - -// this macro takes the address of the argument, but on gcc/clang can accept rvalues -#if defined(STBDS_HAS_LITERAL_ARRAY) && defined(STBDS_HAS_TYPEOF) - #if __clang__ - #define STBDS_ADDRESSOF(typevar, value) ((__typeof__(typevar)[1]){value}) // literal array decays to pointer to value - #else - #define STBDS_ADDRESSOF(typevar, value) ((typeof(typevar)[1]){value}) // literal array decays to pointer to value - #endif -#else -#define STBDS_ADDRESSOF(typevar, value) &(value) -#endif - -#define STBDS_OFFSETOF(var,field) ((char *) &(var)->field - (char *) (var)) - -#define stbds_header(t) ((stbds_array_header *) (t) - 1) -#define stbds_temp(t) stbds_header(t)->temp -#define stbds_temp_key(t) (*(char **) stbds_header(t)->hash_table) - -#define stbds_arrsetcap(a,n) (stbds_arrgrow(a,0,n)) -#define stbds_arrsetlen(a,n) ((stbds_arrcap(a) < (size_t) (n) ? stbds_arrsetcap((a),(size_t)(n)),0 : 0), (a) ? stbds_header(a)->length = (size_t) (n) : 0) -#define stbds_arrcap(a) ((a) ? stbds_header(a)->capacity : 0) -#define stbds_arrlen(a) ((a) ? (ptrdiff_t) stbds_header(a)->length : 0) -#define stbds_arrlenu(a) ((a) ? stbds_header(a)->length : 0) -#define stbds_arrput(a,v) (stbds_arrmaybegrow(a,1), (a)[stbds_header(a)->length++] = (v)) -#define stbds_arrpush stbds_arrput // synonym -#define stbds_arrpop(a) (stbds_header(a)->length--, (a)[stbds_header(a)->length]) -#define stbds_arraddn(a,n) ((void)(stbds_arraddnindex(a, n))) // deprecated, use one of the following instead: -#define stbds_arraddnptr(a,n) (stbds_arrmaybegrow(a,n), (n) ? (stbds_header(a)->length += (n), &(a)[stbds_header(a)->length-(n)]) : (a)) -#define stbds_arraddnindex(a,n)(stbds_arrmaybegrow(a,n), (n) ? (stbds_header(a)->length += (n), stbds_header(a)->length-(n)) : stbds_arrlen(a)) -#define stbds_arraddnoff stbds_arraddnindex -#define stbds_arrlast(a) ((a)[stbds_header(a)->length-1]) -#define stbds_arrfree(a) ((void) ((a) ? STBDS_FREE(NULL,stbds_header(a)) : (void)0), (a)=NULL) -#define stbds_arrdel(a,i) stbds_arrdeln(a,i,1) -#define stbds_arrdeln(a,i,n) (memmove(&(a)[i], &(a)[(i)+(n)], sizeof *(a) * (stbds_header(a)->length-(n)-(i))), stbds_header(a)->length -= (n)) -#define stbds_arrdelswap(a,i) ((a)[i] = stbds_arrlast(a), stbds_header(a)->length -= 1) -#define stbds_arrinsn(a,i,n) (stbds_arraddn((a),(n)), memmove(&(a)[(i)+(n)], &(a)[i], sizeof *(a) * (stbds_header(a)->length-(n)-(i)))) -#define stbds_arrins(a,i,v) (stbds_arrinsn((a),(i),1), (a)[i]=(v)) - -#define stbds_arrmaybegrow(a,n) ((!(a) || stbds_header(a)->length + (n) > stbds_header(a)->capacity) \ - ? (stbds_arrgrow(a,n,0),0) : 0) - -#define stbds_arrgrow(a,b,c) ((a) = stbds_arrgrowf_wrapper((a), sizeof *(a), (b), (c))) - -#define stbds_hmput(t, k, v) \ - ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, 0), \ - (t)[stbds_temp((t)-1)].key = (k), \ - (t)[stbds_temp((t)-1)].value = (v)) - -#define stbds_hmputs(t, s) \ - ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), &(s).key, sizeof (s).key, STBDS_HM_BINARY), \ - (t)[stbds_temp((t)-1)] = (s)) - -#define stbds_hmgeti(t,k) \ - ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, STBDS_HM_BINARY), \ - stbds_temp((t)-1)) - -#define stbds_hmgeti_ts(t,k,temp) \ - ((t) = stbds_hmget_key_ts_wrapper((t), sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, &(temp), STBDS_HM_BINARY), \ - (temp)) - -#define stbds_hmgetp(t, k) \ - ((void) stbds_hmgeti(t,k), &(t)[stbds_temp((t)-1)]) - -#define stbds_hmgetp_ts(t, k, temp) \ - ((void) stbds_hmgeti_ts(t,k,temp), &(t)[temp]) - -#define stbds_hmdel(t,k) \ - (((t) = stbds_hmdel_key_wrapper((t),sizeof *(t), (void*) STBDS_ADDRESSOF((t)->key, (k)), sizeof (t)->key, STBDS_OFFSETOF((t),key), STBDS_HM_BINARY)),(t)?stbds_temp((t)-1):0) - -#define stbds_hmdefault(t, v) \ - ((t) = stbds_hmput_default_wrapper((t), sizeof *(t)), (t)[-1].value = (v)) - -#define stbds_hmdefaults(t, s) \ - ((t) = stbds_hmput_default_wrapper((t), sizeof *(t)), (t)[-1] = (s)) - -#define stbds_hmfree(p) \ - ((void) ((p) != NULL ? stbds_hmfree_func((p)-1,sizeof*(p)),0 : 0),(p)=NULL) - -#define stbds_hmgets(t, k) (*stbds_hmgetp(t,k)) -#define stbds_hmget(t, k) (stbds_hmgetp(t,k)->value) -#define stbds_hmget_ts(t, k, temp) (stbds_hmgetp_ts(t,k,temp)->value) -#define stbds_hmlen(t) ((t) ? (ptrdiff_t) stbds_header((t)-1)->length-1 : 0) -#define stbds_hmlenu(t) ((t) ? stbds_header((t)-1)->length-1 : 0) -#define stbds_hmgetp_null(t,k) (stbds_hmgeti(t,k) == -1 ? NULL : &(t)[stbds_temp((t)-1)]) - -#define stbds_shput(t, k, v) \ - ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \ - (t)[stbds_temp((t)-1)].value = (v)) - -#define stbds_shputi(t, k, v) \ - ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \ - (t)[stbds_temp((t)-1)].value = (v), stbds_temp((t)-1)) - -#define stbds_shputs(t, s) \ - ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (s).key, sizeof (s).key, STBDS_HM_STRING), \ - (t)[stbds_temp((t)-1)] = (s), \ - (t)[stbds_temp((t)-1)].key = stbds_temp_key((t)-1)) // above line overwrites whole structure, so must rewrite key here if it was allocated internally - -#define stbds_pshput(t, p) \ - ((t) = stbds_hmput_key_wrapper((t), sizeof *(t), (void*) (p)->key, sizeof (p)->key, STBDS_HM_PTR_TO_STRING), \ - (t)[stbds_temp((t)-1)] = (p)) - -#define stbds_shgeti(t,k) \ - ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_HM_STRING), \ - stbds_temp((t)-1)) - -#define stbds_pshgeti(t,k) \ - ((t) = stbds_hmget_key_wrapper((t), sizeof *(t), (void*) (k), sizeof (*(t))->key, STBDS_HM_PTR_TO_STRING), \ - stbds_temp((t)-1)) - -#define stbds_shgetp(t, k) \ - ((void) stbds_shgeti(t,k), &(t)[stbds_temp((t)-1)]) - -#define stbds_pshget(t, k) \ - ((void) stbds_pshgeti(t,k), (t)[stbds_temp((t)-1)]) - -#define stbds_shdel(t,k) \ - (((t) = stbds_hmdel_key_wrapper((t),sizeof *(t), (void*) (k), sizeof (t)->key, STBDS_OFFSETOF((t),key), STBDS_HM_STRING)),(t)?stbds_temp((t)-1):0) -#define stbds_pshdel(t,k) \ - (((t) = stbds_hmdel_key_wrapper((t),sizeof *(t), (void*) (k), sizeof (*(t))->key, STBDS_OFFSETOF(*(t),key), STBDS_HM_PTR_TO_STRING)),(t)?stbds_temp((t)-1):0) - -#define stbds_sh_new_arena(t) \ - ((t) = stbds_shmode_func_wrapper(t, sizeof *(t), STBDS_SH_ARENA)) -#define stbds_sh_new_strdup(t) \ - ((t) = stbds_shmode_func_wrapper(t, sizeof *(t), STBDS_SH_STRDUP)) - -#define stbds_shdefault(t, v) stbds_hmdefault(t,v) -#define stbds_shdefaults(t, s) stbds_hmdefaults(t,s) - -#define stbds_shfree stbds_hmfree -#define stbds_shlenu stbds_hmlenu - -#define stbds_shgets(t, k) (*stbds_shgetp(t,k)) -#define stbds_shget(t, k) (stbds_shgetp(t,k)->value) -#define stbds_shgetp_null(t,k) (stbds_shgeti(t,k) == -1 ? NULL : &(t)[stbds_temp((t)-1)]) -#define stbds_shlen stbds_hmlen - -typedef struct -{ - size_t length; - size_t capacity; - void * hash_table; - ptrdiff_t temp; -} stbds_array_header; - -typedef struct stbds_string_block -{ - struct stbds_string_block *next; - char storage[8]; -} stbds_string_block; - -struct stbds_string_arena -{ - stbds_string_block *storage; - size_t remaining; - unsigned char block; - unsigned char mode; // this isn't used by the string arena itself -}; - -#define STBDS_HM_BINARY 0 -#define STBDS_HM_STRING 1 - -enum -{ - STBDS_SH_NONE, - STBDS_SH_DEFAULT, - STBDS_SH_STRDUP, - STBDS_SH_ARENA -}; - -#ifdef __cplusplus -// in C we use implicit assignment from these void*-returning functions to T*. -// in C++ these templates make the same code work -template<class T> static T * stbds_arrgrowf_wrapper(T *a, size_t elemsize, size_t addlen, size_t min_cap) { - return (T*)stbds_arrgrowf((void *)a, elemsize, addlen, min_cap); -} -template<class T> static T * stbds_hmget_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, int mode) { - return (T*)stbds_hmget_key((void*)a, elemsize, key, keysize, mode); -} -template<class T> static T * stbds_hmget_key_ts_wrapper(T *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode) { - return (T*)stbds_hmget_key_ts((void*)a, elemsize, key, keysize, temp, mode); -} -template<class T> static T * stbds_hmput_default_wrapper(T *a, size_t elemsize) { - return (T*)stbds_hmput_default((void *)a, elemsize); -} -template<class T> static T * stbds_hmput_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, int mode) { - return (T*)stbds_hmput_key((void*)a, elemsize, key, keysize, mode); -} -template<class T> static T * stbds_hmdel_key_wrapper(T *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode){ - return (T*)stbds_hmdel_key((void*)a, elemsize, key, keysize, keyoffset, mode); -} -template<class T> static T * stbds_shmode_func_wrapper(T *, size_t elemsize, int mode) { - return (T*)stbds_shmode_func(elemsize, mode); -} -#else -#define stbds_arrgrowf_wrapper stbds_arrgrowf -#define stbds_hmget_key_wrapper stbds_hmget_key -#define stbds_hmget_key_ts_wrapper stbds_hmget_key_ts -#define stbds_hmput_default_wrapper stbds_hmput_default -#define stbds_hmput_key_wrapper stbds_hmput_key -#define stbds_hmdel_key_wrapper stbds_hmdel_key -#define stbds_shmode_func_wrapper(t,e,m) stbds_shmode_func(e,m) -#endif - -#endif // INCLUDE_STB_DS_H - - -////////////////////////////////////////////////////////////////////////////// -// -// IMPLEMENTATION -// - -#ifdef STB_DS_IMPLEMENTATION -#include <assert.h> -#include <string.h> - -#ifndef STBDS_ASSERT -#define STBDS_ASSERT_WAS_UNDEFINED -#define STBDS_ASSERT(x) ((void) 0) -#endif - -#ifdef STBDS_STATISTICS -#define STBDS_STATS(x) x -size_t stbds_array_grow; -size_t stbds_hash_grow; -size_t stbds_hash_shrink; -size_t stbds_hash_rebuild; -size_t stbds_hash_probes; -size_t stbds_hash_alloc; -size_t stbds_rehash_probes; -size_t stbds_rehash_items; -#else -#define STBDS_STATS(x) -#endif - -// -// stbds_arr implementation -// - -//int *prev_allocs[65536]; -//int num_prev; - -void *stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap) -{ - stbds_array_header temp={0}; // force debugging - void *b; - size_t min_len = stbds_arrlen(a) + addlen; - (void) sizeof(temp); - - // compute the minimum capacity needed - if (min_len > min_cap) - min_cap = min_len; - - if (min_cap <= stbds_arrcap(a)) - return a; - - // increase needed capacity to guarantee O(1) amortized - if (min_cap < 2 * stbds_arrcap(a)) - min_cap = 2 * stbds_arrcap(a); - else if (min_cap < 4) - min_cap = 4; - - //if (num_prev < 65536) if (a) prev_allocs[num_prev++] = (int *) ((char *) a+1); - //if (num_prev == 2201) - // num_prev = num_prev; - b = STBDS_REALLOC(NULL, (a) ? stbds_header(a) : 0, elemsize * min_cap + sizeof(stbds_array_header)); - //if (num_prev < 65536) prev_allocs[num_prev++] = (int *) (char *) b; - b = (char *) b + sizeof(stbds_array_header); - if (a == NULL) { - stbds_header(b)->length = 0; - stbds_header(b)->hash_table = 0; - stbds_header(b)->temp = 0; - } else { - STBDS_STATS(++stbds_array_grow); - } - stbds_header(b)->capacity = min_cap; - - return b; -} - -void stbds_arrfreef(void *a) -{ - STBDS_FREE(NULL, stbds_header(a)); -} - -// -// stbds_hm hash table implementation -// - -#ifdef STBDS_INTERNAL_SMALL_BUCKET -#define STBDS_BUCKET_LENGTH 4 -#else -#define STBDS_BUCKET_LENGTH 8 -#endif - -#define STBDS_BUCKET_SHIFT (STBDS_BUCKET_LENGTH == 8 ? 3 : 2) -#define STBDS_BUCKET_MASK (STBDS_BUCKET_LENGTH-1) -#define STBDS_CACHE_LINE_SIZE 64 - -#define STBDS_ALIGN_FWD(n,a) (((n) + (a) - 1) & ~((a)-1)) - -typedef struct -{ - size_t hash [STBDS_BUCKET_LENGTH]; - ptrdiff_t index[STBDS_BUCKET_LENGTH]; -} stbds_hash_bucket; // in 32-bit, this is one 64-byte cache line; in 64-bit, each array is one 64-byte cache line - -typedef struct -{ - char * temp_key; // this MUST be the first field of the hash table - size_t slot_count; - size_t used_count; - size_t used_count_threshold; - size_t used_count_shrink_threshold; - size_t tombstone_count; - size_t tombstone_count_threshold; - size_t seed; - size_t slot_count_log2; - stbds_string_arena string; - stbds_hash_bucket *storage; // not a separate allocation, just 64-byte aligned storage after this struct -} stbds_hash_index; - -#define STBDS_INDEX_EMPTY -1 -#define STBDS_INDEX_DELETED -2 -#define STBDS_INDEX_IN_USE(x) ((x) >= 0) - -#define STBDS_HASH_EMPTY 0 -#define STBDS_HASH_DELETED 1 - -static size_t stbds_hash_seed=0x31415926; - -void stbds_rand_seed(size_t seed) -{ - stbds_hash_seed = seed; -} - -#define stbds_load_32_or_64(var, temp, v32, v64_hi, v64_lo) \ - temp = v64_lo ^ v32, temp <<= 16, temp <<= 16, temp >>= 16, temp >>= 16, /* discard if 32-bit */ \ - var = v64_hi, var <<= 16, var <<= 16, /* discard if 32-bit */ \ - var ^= temp ^ v32 - -#define STBDS_SIZE_T_BITS ((sizeof (size_t)) * 8) - -static size_t stbds_probe_position(size_t hash, size_t slot_count, size_t slot_log2) -{ - size_t pos; - STBDS_NOTUSED(slot_log2); - pos = hash & (slot_count-1); - #ifdef STBDS_INTERNAL_BUCKET_START - pos &= ~STBDS_BUCKET_MASK; - #endif - return pos; -} - -static size_t stbds_log2(size_t slot_count) -{ - size_t n=0; - while (slot_count > 1) { - slot_count >>= 1; - ++n; - } - return n; -} - -static stbds_hash_index *stbds_make_hash_index(size_t slot_count, stbds_hash_index *ot) -{ - stbds_hash_index *t; - t = (stbds_hash_index *) STBDS_REALLOC(NULL,0,(slot_count >> STBDS_BUCKET_SHIFT) * sizeof(stbds_hash_bucket) + sizeof(stbds_hash_index) + STBDS_CACHE_LINE_SIZE-1); - t->storage = (stbds_hash_bucket *) STBDS_ALIGN_FWD((size_t) (t+1), STBDS_CACHE_LINE_SIZE); - t->slot_count = slot_count; - t->slot_count_log2 = stbds_log2(slot_count); - t->tombstone_count = 0; - t->used_count = 0; - - #if 0 // A1 - t->used_count_threshold = slot_count*12/16; // if 12/16th of table is occupied, grow - t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild - t->used_count_shrink_threshold = slot_count* 4/16; // if table is only 4/16th full, shrink - #elif 1 // A2 - //t->used_count_threshold = slot_count*12/16; // if 12/16th of table is occupied, grow - //t->tombstone_count_threshold = slot_count* 3/16; // if tombstones are 3/16th of table, rebuild - //t->used_count_shrink_threshold = slot_count* 4/16; // if table is only 4/16th full, shrink - - // compute without overflowing - t->used_count_threshold = slot_count - (slot_count>>2); - t->tombstone_count_threshold = (slot_count>>3) + (slot_count>>4); - t->used_count_shrink_threshold = slot_count >> 2; - - #elif 0 // B1 - t->used_count_threshold = slot_count*13/16; // if 13/16th of table is occupied, grow - t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild - t->used_count_shrink_threshold = slot_count* 5/16; // if table is only 5/16th full, shrink - #else // C1 - t->used_count_threshold = slot_count*14/16; // if 14/16th of table is occupied, grow - t->tombstone_count_threshold = slot_count* 2/16; // if tombstones are 2/16th of table, rebuild - t->used_count_shrink_threshold = slot_count* 6/16; // if table is only 6/16th full, shrink - #endif - // Following statistics were measured on a Core i7-6700 @ 4.00Ghz, compiled with clang 7.0.1 -O2 - // Note that the larger tables have high variance as they were run fewer times - // A1 A2 B1 C1 - // 0.10ms : 0.10ms : 0.10ms : 0.11ms : 2,000 inserts creating 2K table - // 0.96ms : 0.95ms : 0.97ms : 1.04ms : 20,000 inserts creating 20K table - // 14.48ms : 14.46ms : 10.63ms : 11.00ms : 200,000 inserts creating 200K table - // 195.74ms : 196.35ms : 203.69ms : 214.92ms : 2,000,000 inserts creating 2M table - // 2193.88ms : 2209.22ms : 2285.54ms : 2437.17ms : 20,000,000 inserts creating 20M table - // 65.27ms : 53.77ms : 65.33ms : 65.47ms : 500,000 inserts & deletes in 2K table - // 72.78ms : 62.45ms : 71.95ms : 72.85ms : 500,000 inserts & deletes in 20K table - // 89.47ms : 77.72ms : 96.49ms : 96.75ms : 500,000 inserts & deletes in 200K table - // 97.58ms : 98.14ms : 97.18ms : 97.53ms : 500,000 inserts & deletes in 2M table - // 118.61ms : 119.62ms : 120.16ms : 118.86ms : 500,000 inserts & deletes in 20M table - // 192.11ms : 194.39ms : 196.38ms : 195.73ms : 500,000 inserts & deletes in 200M table - - if (slot_count <= STBDS_BUCKET_LENGTH) - t->used_count_shrink_threshold = 0; - // to avoid infinite loop, we need to guarantee that at least one slot is empty and will terminate probes - STBDS_ASSERT(t->used_count_threshold + t->tombstone_count_threshold < t->slot_count); - STBDS_STATS(++stbds_hash_alloc); - if (ot) { - t->string = ot->string; - // reuse old seed so we can reuse old hashes so below "copy out old data" doesn't do any hashing - t->seed = ot->seed; - } else { - size_t a,b,temp; - memset(&t->string, 0, sizeof(t->string)); - t->seed = stbds_hash_seed; - // LCG - // in 32-bit, a = 2147001325 b = 715136305 - // in 64-bit, a = 2862933555777941757 b = 3037000493 - stbds_load_32_or_64(a,temp, 2147001325, 0x27bb2ee6, 0x87b0b0fd); - stbds_load_32_or_64(b,temp, 715136305, 0, 0xb504f32d); - stbds_hash_seed = stbds_hash_seed * a + b; - } - - { - size_t i,j; - for (i=0; i < slot_count >> STBDS_BUCKET_SHIFT; ++i) { - stbds_hash_bucket *b = &t->storage[i]; - for (j=0; j < STBDS_BUCKET_LENGTH; ++j) - b->hash[j] = STBDS_HASH_EMPTY; - for (j=0; j < STBDS_BUCKET_LENGTH; ++j) - b->index[j] = STBDS_INDEX_EMPTY; - } - } - - // copy out the old data, if any - if (ot) { - size_t i,j; - t->used_count = ot->used_count; - for (i=0; i < ot->slot_count >> STBDS_BUCKET_SHIFT; ++i) { - stbds_hash_bucket *ob = &ot->storage[i]; - for (j=0; j < STBDS_BUCKET_LENGTH; ++j) { - if (STBDS_INDEX_IN_USE(ob->index[j])) { - size_t hash = ob->hash[j]; - size_t pos = stbds_probe_position(hash, t->slot_count, t->slot_count_log2); - size_t step = STBDS_BUCKET_LENGTH; - STBDS_STATS(++stbds_rehash_items); - for (;;) { - size_t limit,z; - stbds_hash_bucket *bucket; - bucket = &t->storage[pos >> STBDS_BUCKET_SHIFT]; - STBDS_STATS(++stbds_rehash_probes); - - for (z=pos & STBDS_BUCKET_MASK; z < STBDS_BUCKET_LENGTH; ++z) { - if (bucket->hash[z] == 0) { - bucket->hash[z] = hash; - bucket->index[z] = ob->index[j]; - goto done; - } - } - - limit = pos & STBDS_BUCKET_MASK; - for (z = 0; z < limit; ++z) { - if (bucket->hash[z] == 0) { - bucket->hash[z] = hash; - bucket->index[z] = ob->index[j]; - goto done; - } - } - - pos += step; // quadratic probing - step += STBDS_BUCKET_LENGTH; - pos &= (t->slot_count-1); - } - } - done: - ; - } - } - } - - return t; -} - -#define STBDS_ROTATE_LEFT(val, n) (((val) << (n)) | ((val) >> (STBDS_SIZE_T_BITS - (n)))) -#define STBDS_ROTATE_RIGHT(val, n) (((val) >> (n)) | ((val) << (STBDS_SIZE_T_BITS - (n)))) - -size_t stbds_hash_string(char *str, size_t seed) -{ - size_t hash = seed; - while (*str) - hash = STBDS_ROTATE_LEFT(hash, 9) + (unsigned char) *str++; - - // Thomas Wang 64-to-32 bit mix function, hopefully also works in 32 bits - hash ^= seed; - hash = (~hash) + (hash << 18); - hash ^= hash ^ STBDS_ROTATE_RIGHT(hash,31); - hash = hash * 21; - hash ^= hash ^ STBDS_ROTATE_RIGHT(hash,11); - hash += (hash << 6); - hash ^= STBDS_ROTATE_RIGHT(hash,22); - return hash+seed; -} - -#ifdef STBDS_SIPHASH_2_4 -#define STBDS_SIPHASH_C_ROUNDS 2 -#define STBDS_SIPHASH_D_ROUNDS 4 -typedef int STBDS_SIPHASH_2_4_can_only_be_used_in_64_bit_builds[sizeof(size_t) == 8 ? 1 : -1]; -#endif - -#ifndef STBDS_SIPHASH_C_ROUNDS -#define STBDS_SIPHASH_C_ROUNDS 1 -#endif -#ifndef STBDS_SIPHASH_D_ROUNDS -#define STBDS_SIPHASH_D_ROUNDS 1 -#endif - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4127) // conditional expression is constant, for do..while(0) and sizeof()== -#endif - -static size_t stbds_siphash_bytes(void *p, size_t len, size_t seed) -{ - unsigned char *d = (unsigned char *) p; - size_t i,j; - size_t v0,v1,v2,v3, data; - - // hash that works on 32- or 64-bit registers without knowing which we have - // (computes different results on 32-bit and 64-bit platform) - // derived from siphash, but on 32-bit platforms very different as it uses 4 32-bit state not 4 64-bit - v0 = ((((size_t) 0x736f6d65 << 16) << 16) + 0x70736575) ^ seed; - v1 = ((((size_t) 0x646f7261 << 16) << 16) + 0x6e646f6d) ^ ~seed; - v2 = ((((size_t) 0x6c796765 << 16) << 16) + 0x6e657261) ^ seed; - v3 = ((((size_t) 0x74656462 << 16) << 16) + 0x79746573) ^ ~seed; - - #ifdef STBDS_TEST_SIPHASH_2_4 - // hardcoded with key material in the siphash test vectors - v0 ^= 0x0706050403020100ull ^ seed; - v1 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed; - v2 ^= 0x0706050403020100ull ^ seed; - v3 ^= 0x0f0e0d0c0b0a0908ull ^ ~seed; - #endif - - #define STBDS_SIPROUND() \ - do { \ - v0 += v1; v1 = STBDS_ROTATE_LEFT(v1, 13); v1 ^= v0; v0 = STBDS_ROTATE_LEFT(v0,STBDS_SIZE_T_BITS/2); \ - v2 += v3; v3 = STBDS_ROTATE_LEFT(v3, 16); v3 ^= v2; \ - v2 += v1; v1 = STBDS_ROTATE_LEFT(v1, 17); v1 ^= v2; v2 = STBDS_ROTATE_LEFT(v2,STBDS_SIZE_T_BITS/2); \ - v0 += v3; v3 = STBDS_ROTATE_LEFT(v3, 21); v3 ^= v0; \ - } while (0) - - for (i=0; i+sizeof(size_t) <= len; i += sizeof(size_t), d += sizeof(size_t)) { - data = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); - data |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // discarded if size_t == 4 - - v3 ^= data; - for (j=0; j < STBDS_SIPHASH_C_ROUNDS; ++j) - STBDS_SIPROUND(); - v0 ^= data; - } - data = len << (STBDS_SIZE_T_BITS-8); - switch (len - i) { - case 7: data |= ((size_t) d[6] << 24) << 24; // fall through - case 6: data |= ((size_t) d[5] << 20) << 20; // fall through - case 5: data |= ((size_t) d[4] << 16) << 16; // fall through - case 4: data |= (d[3] << 24); // fall through - case 3: data |= (d[2] << 16); // fall through - case 2: data |= (d[1] << 8); // fall through - case 1: data |= d[0]; // fall through - case 0: break; - } - v3 ^= data; - for (j=0; j < STBDS_SIPHASH_C_ROUNDS; ++j) - STBDS_SIPROUND(); - v0 ^= data; - v2 ^= 0xff; - for (j=0; j < STBDS_SIPHASH_D_ROUNDS; ++j) - STBDS_SIPROUND(); - -#ifdef STBDS_SIPHASH_2_4 - return v0^v1^v2^v3; -#else - return v1^v2^v3; // slightly stronger since v0^v3 in above cancels out final round operation? I tweeted at the authors of SipHash about this but they didn't reply -#endif -} - -size_t stbds_hash_bytes(void *p, size_t len, size_t seed) -{ -#ifdef STBDS_SIPHASH_2_4 - return stbds_siphash_bytes(p,len,seed); -#else - unsigned char *d = (unsigned char *) p; - - if (len == 4) { - unsigned int hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); - #if 0 - // HASH32-A Bob Jenkin's hash function w/o large constants - hash ^= seed; - hash -= (hash<<6); - hash ^= (hash>>17); - hash -= (hash<<9); - hash ^= seed; - hash ^= (hash<<4); - hash -= (hash<<3); - hash ^= (hash<<10); - hash ^= (hash>>15); - #elif 1 - // HASH32-BB Bob Jenkin's presumably-accidental version of Thomas Wang hash with rotates turned into shifts. - // Note that converting these back to rotates makes it run a lot slower, presumably due to collisions, so I'm - // not really sure what's going on. - hash ^= seed; - hash = (hash ^ 61) ^ (hash >> 16); - hash = hash + (hash << 3); - hash = hash ^ (hash >> 4); - hash = hash * 0x27d4eb2d; - hash ^= seed; - hash = hash ^ (hash >> 15); - #else // HASH32-C - Murmur3 - hash ^= seed; - hash *= 0xcc9e2d51; - hash = (hash << 17) | (hash >> 15); - hash *= 0x1b873593; - hash ^= seed; - hash = (hash << 19) | (hash >> 13); - hash = hash*5 + 0xe6546b64; - hash ^= hash >> 16; - hash *= 0x85ebca6b; - hash ^= seed; - hash ^= hash >> 13; - hash *= 0xc2b2ae35; - hash ^= hash >> 16; - #endif - // Following statistics were measured on a Core i7-6700 @ 4.00Ghz, compiled with clang 7.0.1 -O2 - // Note that the larger tables have high variance as they were run fewer times - // HASH32-A // HASH32-BB // HASH32-C - // 0.10ms // 0.10ms // 0.10ms : 2,000 inserts creating 2K table - // 0.96ms // 0.95ms // 0.99ms : 20,000 inserts creating 20K table - // 14.69ms // 14.43ms // 14.97ms : 200,000 inserts creating 200K table - // 199.99ms // 195.36ms // 202.05ms : 2,000,000 inserts creating 2M table - // 2234.84ms // 2187.74ms // 2240.38ms : 20,000,000 inserts creating 20M table - // 55.68ms // 53.72ms // 57.31ms : 500,000 inserts & deletes in 2K table - // 63.43ms // 61.99ms // 65.73ms : 500,000 inserts & deletes in 20K table - // 80.04ms // 77.96ms // 81.83ms : 500,000 inserts & deletes in 200K table - // 100.42ms // 97.40ms // 102.39ms : 500,000 inserts & deletes in 2M table - // 119.71ms // 120.59ms // 121.63ms : 500,000 inserts & deletes in 20M table - // 185.28ms // 195.15ms // 187.74ms : 500,000 inserts & deletes in 200M table - // 15.58ms // 14.79ms // 15.52ms : 200,000 inserts creating 200K table with varying key spacing - - return (((size_t) hash << 16 << 16) | hash) ^ seed; - } else if (len == 8 && sizeof(size_t) == 8) { - size_t hash = d[0] | (d[1] << 8) | (d[2] << 16) | (d[3] << 24); - hash |= (size_t) (d[4] | (d[5] << 8) | (d[6] << 16) | (d[7] << 24)) << 16 << 16; // avoid warning if size_t == 4 - hash ^= seed; - hash = (~hash) + (hash << 21); - hash ^= STBDS_ROTATE_RIGHT(hash,24); - hash *= 265; - hash ^= STBDS_ROTATE_RIGHT(hash,14); - hash ^= seed; - hash *= 21; - hash ^= STBDS_ROTATE_RIGHT(hash,28); - hash += (hash << 31); - hash = (~hash) + (hash << 18); - return hash; - } else { - return stbds_siphash_bytes(p,len,seed); - } -#endif -} -#ifdef _MSC_VER -#pragma warning(pop) -#endif - - -static int stbds_is_key_equal(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode, size_t i) -{ - if (mode >= STBDS_HM_STRING) - return 0==strcmp((char *) key, * (char **) ((char *) a + elemsize*i + keyoffset)); - else - return 0==memcmp(key, (char *) a + elemsize*i + keyoffset, keysize); -} - -#define STBDS_HASH_TO_ARR(x,elemsize) ((char*) (x) - (elemsize)) -#define STBDS_ARR_TO_HASH(x,elemsize) ((char*) (x) + (elemsize)) - -#define stbds_hash_table(a) ((stbds_hash_index *) stbds_header(a)->hash_table) - -void stbds_hmfree_func(void *a, size_t elemsize) -{ - if (a == NULL) return; - if (stbds_hash_table(a) != NULL) { - if (stbds_hash_table(a)->string.mode == STBDS_SH_STRDUP) { - size_t i; - // skip 0th element, which is default - for (i=1; i < stbds_header(a)->length; ++i) - STBDS_FREE(NULL, *(char**) ((char *) a + elemsize*i)); - } - stbds_strreset(&stbds_hash_table(a)->string); - } - STBDS_FREE(NULL, stbds_header(a)->hash_table); - STBDS_FREE(NULL, stbds_header(a)); -} - -static ptrdiff_t stbds_hm_find_slot(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode) -{ - void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); - stbds_hash_index *table = stbds_hash_table(raw_a); - size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key,table->seed) : stbds_hash_bytes(key, keysize,table->seed); - size_t step = STBDS_BUCKET_LENGTH; - size_t limit,i; - size_t pos; - stbds_hash_bucket *bucket; - - if (hash < 2) hash += 2; // stored hash values are forbidden from being 0, so we can detect empty slots - - pos = stbds_probe_position(hash, table->slot_count, table->slot_count_log2); - - for (;;) { - STBDS_STATS(++stbds_hash_probes); - bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; - - // start searching from pos to end of bucket, this should help performance on small hash tables that fit in cache - for (i=pos & STBDS_BUCKET_MASK; i < STBDS_BUCKET_LENGTH; ++i) { - if (bucket->hash[i] == hash) { - if (stbds_is_key_equal(a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { - return (pos & ~STBDS_BUCKET_MASK)+i; - } - } else if (bucket->hash[i] == STBDS_HASH_EMPTY) { - return -1; - } - } - - // search from beginning of bucket to pos - limit = pos & STBDS_BUCKET_MASK; - for (i = 0; i < limit; ++i) { - if (bucket->hash[i] == hash) { - if (stbds_is_key_equal(a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { - return (pos & ~STBDS_BUCKET_MASK)+i; - } - } else if (bucket->hash[i] == STBDS_HASH_EMPTY) { - return -1; - } - } - - // quadratic probing - pos += step; - step += STBDS_BUCKET_LENGTH; - pos &= (table->slot_count-1); - } - /* NOTREACHED */ -} - -void * stbds_hmget_key_ts(void *a, size_t elemsize, void *key, size_t keysize, ptrdiff_t *temp, int mode) -{ - size_t keyoffset = 0; - if (a == NULL) { - // make it non-empty so we can return a temp - a = stbds_arrgrowf(0, elemsize, 0, 1); - stbds_header(a)->length += 1; - memset(a, 0, elemsize); - *temp = STBDS_INDEX_EMPTY; - // adjust a to point after the default element - return STBDS_ARR_TO_HASH(a,elemsize); - } else { - stbds_hash_index *table; - void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); - // adjust a to point to the default element - table = (stbds_hash_index *) stbds_header(raw_a)->hash_table; - if (table == 0) { - *temp = -1; - } else { - ptrdiff_t slot = stbds_hm_find_slot(a, elemsize, key, keysize, keyoffset, mode); - if (slot < 0) { - *temp = STBDS_INDEX_EMPTY; - } else { - stbds_hash_bucket *b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; - *temp = b->index[slot & STBDS_BUCKET_MASK]; - } - } - return a; - } -} - -void * stbds_hmget_key(void *a, size_t elemsize, void *key, size_t keysize, int mode) -{ - ptrdiff_t temp; - void *p = stbds_hmget_key_ts(a, elemsize, key, keysize, &temp, mode); - stbds_temp(STBDS_HASH_TO_ARR(p,elemsize)) = temp; - return p; -} - -void * stbds_hmput_default(void *a, size_t elemsize) -{ - // three cases: - // a is NULL <- allocate - // a has a hash table but no entries, because of shmode <- grow - // a has entries <- do nothing - if (a == NULL || stbds_header(STBDS_HASH_TO_ARR(a,elemsize))->length == 0) { - a = stbds_arrgrowf(a ? STBDS_HASH_TO_ARR(a,elemsize) : NULL, elemsize, 0, 1); - stbds_header(a)->length += 1; - memset(a, 0, elemsize); - a=STBDS_ARR_TO_HASH(a,elemsize); - } - return a; -} - -static char *stbds_strdup(char *str); - -void *stbds_hmput_key(void *a, size_t elemsize, void *key, size_t keysize, int mode) -{ - size_t keyoffset=0; - void *raw_a; - stbds_hash_index *table; - - if (a == NULL) { - a = stbds_arrgrowf(0, elemsize, 0, 1); - memset(a, 0, elemsize); - stbds_header(a)->length += 1; - // adjust a to point AFTER the default element - a = STBDS_ARR_TO_HASH(a,elemsize); - } - - // adjust a to point to the default element - raw_a = a; - a = STBDS_HASH_TO_ARR(a,elemsize); - - table = (stbds_hash_index *) stbds_header(a)->hash_table; - - if (table == NULL || table->used_count >= table->used_count_threshold) { - stbds_hash_index *nt; - size_t slot_count; - - slot_count = (table == NULL) ? STBDS_BUCKET_LENGTH : table->slot_count*2; - nt = stbds_make_hash_index(slot_count, table); - if (table) - STBDS_FREE(NULL, table); - else - nt->string.mode = mode >= STBDS_HM_STRING ? STBDS_SH_DEFAULT : 0; - stbds_header(a)->hash_table = table = nt; - STBDS_STATS(++stbds_hash_grow); - } - - // we iterate hash table explicitly because we want to track if we saw a tombstone - { - size_t hash = mode >= STBDS_HM_STRING ? stbds_hash_string((char*)key,table->seed) : stbds_hash_bytes(key, keysize,table->seed); - size_t step = STBDS_BUCKET_LENGTH; - size_t pos; - ptrdiff_t tombstone = -1; - stbds_hash_bucket *bucket; - - // stored hash values are forbidden from being 0, so we can detect empty slots to early out quickly - if (hash < 2) hash += 2; - - pos = stbds_probe_position(hash, table->slot_count, table->slot_count_log2); - - for (;;) { - size_t limit, i; - STBDS_STATS(++stbds_hash_probes); - bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; - - // start searching from pos to end of bucket - for (i=pos & STBDS_BUCKET_MASK; i < STBDS_BUCKET_LENGTH; ++i) { - if (bucket->hash[i] == hash) { - if (stbds_is_key_equal(raw_a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { - stbds_temp(a) = bucket->index[i]; - if (mode >= STBDS_HM_STRING) - stbds_temp_key(a) = * (char **) ((char *) raw_a + elemsize*bucket->index[i] + keyoffset); - return STBDS_ARR_TO_HASH(a,elemsize); - } - } else if (bucket->hash[i] == 0) { - pos = (pos & ~STBDS_BUCKET_MASK) + i; - goto found_empty_slot; - } else if (tombstone < 0) { - if (bucket->index[i] == STBDS_INDEX_DELETED) - tombstone = (ptrdiff_t) ((pos & ~STBDS_BUCKET_MASK) + i); - } - } - - // search from beginning of bucket to pos - limit = pos & STBDS_BUCKET_MASK; - for (i = 0; i < limit; ++i) { - if (bucket->hash[i] == hash) { - if (stbds_is_key_equal(raw_a, elemsize, key, keysize, keyoffset, mode, bucket->index[i])) { - stbds_temp(a) = bucket->index[i]; - return STBDS_ARR_TO_HASH(a,elemsize); - } - } else if (bucket->hash[i] == 0) { - pos = (pos & ~STBDS_BUCKET_MASK) + i; - goto found_empty_slot; - } else if (tombstone < 0) { - if (bucket->index[i] == STBDS_INDEX_DELETED) - tombstone = (ptrdiff_t) ((pos & ~STBDS_BUCKET_MASK) + i); - } - } - - // quadratic probing - pos += step; - step += STBDS_BUCKET_LENGTH; - pos &= (table->slot_count-1); - } - found_empty_slot: - if (tombstone >= 0) { - pos = tombstone; - --table->tombstone_count; - } - ++table->used_count; - - { - ptrdiff_t i = (ptrdiff_t) stbds_arrlen(a); - // we want to do stbds_arraddn(1), but we can't use the macros since we don't have something of the right type - if ((size_t) i+1 > stbds_arrcap(a)) - *(void **) &a = stbds_arrgrowf(a, elemsize, 1, 0); - raw_a = STBDS_ARR_TO_HASH(a,elemsize); - - STBDS_ASSERT((size_t) i+1 <= stbds_arrcap(a)); - stbds_header(a)->length = i+1; - bucket = &table->storage[pos >> STBDS_BUCKET_SHIFT]; - bucket->hash[pos & STBDS_BUCKET_MASK] = hash; - bucket->index[pos & STBDS_BUCKET_MASK] = i-1; - stbds_temp(a) = i-1; - - switch (table->string.mode) { - case STBDS_SH_STRDUP: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = stbds_strdup((char*) key); break; - case STBDS_SH_ARENA: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = stbds_stralloc(&table->string, (char*)key); break; - case STBDS_SH_DEFAULT: stbds_temp_key(a) = *(char **) ((char *) a + elemsize*i) = (char *) key; break; - default: memcpy((char *) a + elemsize*i, key, keysize); break; - } - } - return STBDS_ARR_TO_HASH(a,elemsize); - } -} - -void * stbds_shmode_func(size_t elemsize, int mode) -{ - void *a = stbds_arrgrowf(0, elemsize, 0, 1); - stbds_hash_index *h; - memset(a, 0, elemsize); - stbds_header(a)->length = 1; - stbds_header(a)->hash_table = h = (stbds_hash_index *) stbds_make_hash_index(STBDS_BUCKET_LENGTH, NULL); - h->string.mode = (unsigned char) mode; - return STBDS_ARR_TO_HASH(a,elemsize); -} - -void * stbds_hmdel_key(void *a, size_t elemsize, void *key, size_t keysize, size_t keyoffset, int mode) -{ - if (a == NULL) { - return 0; - } else { - stbds_hash_index *table; - void *raw_a = STBDS_HASH_TO_ARR(a,elemsize); - table = (stbds_hash_index *) stbds_header(raw_a)->hash_table; - stbds_temp(raw_a) = 0; - if (table == 0) { - return a; - } else { - ptrdiff_t slot; - slot = stbds_hm_find_slot(a, elemsize, key, keysize, keyoffset, mode); - if (slot < 0) - return a; - else { - stbds_hash_bucket *b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; - int i = slot & STBDS_BUCKET_MASK; - ptrdiff_t old_index = b->index[i]; - ptrdiff_t final_index = (ptrdiff_t) stbds_arrlen(raw_a)-1-1; // minus one for the raw_a vs a, and minus one for 'last' - STBDS_ASSERT(slot < (ptrdiff_t) table->slot_count); - --table->used_count; - ++table->tombstone_count; - stbds_temp(raw_a) = 1; - STBDS_ASSERT(table->used_count >= 0); - //STBDS_ASSERT(table->tombstone_count < table->slot_count/4); - b->hash[i] = STBDS_HASH_DELETED; - b->index[i] = STBDS_INDEX_DELETED; - - if (mode == STBDS_HM_STRING && table->string.mode == STBDS_SH_STRDUP) - STBDS_FREE(NULL, *(char**) ((char *) a+elemsize*old_index)); - - // if indices are the same, memcpy is a no-op, but back-pointer-fixup will fail, so skip - if (old_index != final_index) { - // swap delete - memmove((char*) a + elemsize*old_index, (char*) a + elemsize*final_index, elemsize); - - // now find the slot for the last element - if (mode == STBDS_HM_STRING) - slot = stbds_hm_find_slot(a, elemsize, *(char**) ((char *) a+elemsize*old_index + keyoffset), keysize, keyoffset, mode); - else - slot = stbds_hm_find_slot(a, elemsize, (char* ) a+elemsize*old_index + keyoffset, keysize, keyoffset, mode); - STBDS_ASSERT(slot >= 0); - b = &table->storage[slot >> STBDS_BUCKET_SHIFT]; - i = slot & STBDS_BUCKET_MASK; - STBDS_ASSERT(b->index[i] == final_index); - b->index[i] = old_index; - } - stbds_header(raw_a)->length -= 1; - - if (table->used_count < table->used_count_shrink_threshold && table->slot_count > STBDS_BUCKET_LENGTH) { - stbds_header(raw_a)->hash_table = stbds_make_hash_index(table->slot_count>>1, table); - STBDS_FREE(NULL, table); - STBDS_STATS(++stbds_hash_shrink); - } else if (table->tombstone_count > table->tombstone_count_threshold) { - stbds_header(raw_a)->hash_table = stbds_make_hash_index(table->slot_count , table); - STBDS_FREE(NULL, table); - STBDS_STATS(++stbds_hash_rebuild); - } - - return a; - } - } - } - /* NOTREACHED */ -} - -static char *stbds_strdup(char *str) -{ - // to keep replaceable allocator simple, we don't want to use strdup. - // rolling our own also avoids problem of strdup vs _strdup - size_t len = strlen(str)+1; - char *p = (char*) STBDS_REALLOC(NULL, 0, len); - memmove(p, str, len); - return p; -} - -#ifndef STBDS_STRING_ARENA_BLOCKSIZE_MIN -#define STBDS_STRING_ARENA_BLOCKSIZE_MIN 512u -#endif -#ifndef STBDS_STRING_ARENA_BLOCKSIZE_MAX -#define STBDS_STRING_ARENA_BLOCKSIZE_MAX (1u<<20) -#endif - -char *stbds_stralloc(stbds_string_arena *a, char *str) -{ - char *p; - size_t len = strlen(str)+1; - if (len > a->remaining) { - // compute the next blocksize - size_t blocksize = a->block; - - // size is 512, 512, 1024, 1024, 2048, 2048, 4096, 4096, etc., so that - // there are log(SIZE) allocations to free when we destroy the table - blocksize = (size_t) (STBDS_STRING_ARENA_BLOCKSIZE_MIN) << (blocksize>>1); - - // if size is under 1M, advance to next blocktype - if (blocksize < (size_t)(STBDS_STRING_ARENA_BLOCKSIZE_MAX)) - ++a->block; - - if (len > blocksize) { - // if string is larger than blocksize, then just allocate the full size. - // note that we still advance string_block so block size will continue - // increasing, so e.g. if somebody only calls this with 1000-long strings, - // eventually the arena will start doubling and handling those as well - stbds_string_block *sb = (stbds_string_block *) STBDS_REALLOC(NULL, 0, sizeof(*sb)-8 + len); - memmove(sb->storage, str, len); - if (a->storage) { - // insert it after the first element, so that we don't waste the space there - sb->next = a->storage->next; - a->storage->next = sb; - } else { - sb->next = 0; - a->storage = sb; - a->remaining = 0; // this is redundant, but good for clarity - } - return sb->storage; - } else { - stbds_string_block *sb = (stbds_string_block *) STBDS_REALLOC(NULL, 0, sizeof(*sb)-8 + blocksize); - sb->next = a->storage; - a->storage = sb; - a->remaining = blocksize; - } - } - - STBDS_ASSERT(len <= a->remaining); - p = a->storage->storage + a->remaining - len; - a->remaining -= len; - memmove(p, str, len); - return p; -} - -void stbds_strreset(stbds_string_arena *a) -{ - stbds_string_block *x,*y; - x = a->storage; - while (x) { - y = x->next; - STBDS_FREE(NULL, x); - x = y; - } - memset(a, 0, sizeof(*a)); -} - -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// UNIT TESTS -// - -#ifdef STBDS_UNIT_TESTS -#include <stdio.h> -#ifdef STBDS_ASSERT_WAS_UNDEFINED -#undef STBDS_ASSERT -#endif -#ifndef STBDS_ASSERT -#define STBDS_ASSERT assert -#include <assert.h> -#endif - -typedef struct { int key,b,c,d; } stbds_struct; -typedef struct { int key[2],b,c,d; } stbds_struct2; - -static char buffer[256]; -char *strkey(int n) -{ -#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__) - sprintf_s(buffer, sizeof(buffer), "test_%d", n); -#else - sprintf(buffer, "test_%d", n); -#endif - return buffer; -} - -void stbds_unit_tests(void) -{ -#if defined(_MSC_VER) && _MSC_VER <= 1200 && defined(__cplusplus) - // VC6 C++ doesn't like the template<> trick on unnamed structures, so do nothing! - STBDS_ASSERT(0); -#else - const int testsize = 100000; - const int testsize2 = testsize/20; - int *arr=NULL; - struct { int key; int value; } *intmap = NULL; - struct { char *key; int value; } *strmap = NULL, s; - struct { stbds_struct key; int value; } *map = NULL; - stbds_struct *map2 = NULL; - stbds_struct2 *map3 = NULL; - stbds_string_arena sa = { 0 }; - int key3[2] = { 1,2 }; - ptrdiff_t temp; - - int i,j; - - STBDS_ASSERT(arrlen(arr)==0); - for (i=0; i < 20000; i += 50) { - for (j=0; j < i; ++j) - arrpush(arr,j); - arrfree(arr); - } - - for (i=0; i < 4; ++i) { - arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); - arrdel(arr,i); - arrfree(arr); - arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); - arrdelswap(arr,i); - arrfree(arr); - } - - for (i=0; i < 5; ++i) { - arrpush(arr,1); arrpush(arr,2); arrpush(arr,3); arrpush(arr,4); - stbds_arrins(arr,i,5); - STBDS_ASSERT(arr[i] == 5); - if (i < 4) - STBDS_ASSERT(arr[4] == 4); - arrfree(arr); - } - - i = 1; - STBDS_ASSERT(hmgeti(intmap,i) == -1); - hmdefault(intmap, -2); - STBDS_ASSERT(hmgeti(intmap, i) == -1); - STBDS_ASSERT(hmget (intmap, i) == -2); - for (i=0; i < testsize; i+=2) - hmput(intmap, i, i*5); - for (i=0; i < testsize; i+=1) { - if (i & 1) STBDS_ASSERT(hmget(intmap, i) == -2 ); - else STBDS_ASSERT(hmget(intmap, i) == i*5); - if (i & 1) STBDS_ASSERT(hmget_ts(intmap, i, temp) == -2 ); - else STBDS_ASSERT(hmget_ts(intmap, i, temp) == i*5); - } - for (i=0; i < testsize; i+=2) - hmput(intmap, i, i*3); - for (i=0; i < testsize; i+=1) - if (i & 1) STBDS_ASSERT(hmget(intmap, i) == -2 ); - else STBDS_ASSERT(hmget(intmap, i) == i*3); - for (i=2; i < testsize; i+=4) - hmdel(intmap, i); // delete half the entries - for (i=0; i < testsize; i+=1) - if (i & 3) STBDS_ASSERT(hmget(intmap, i) == -2 ); - else STBDS_ASSERT(hmget(intmap, i) == i*3); - for (i=0; i < testsize; i+=1) - hmdel(intmap, i); // delete the rest of the entries - for (i=0; i < testsize; i+=1) - STBDS_ASSERT(hmget(intmap, i) == -2 ); - hmfree(intmap); - for (i=0; i < testsize; i+=2) - hmput(intmap, i, i*3); - hmfree(intmap); - - #if defined(__clang__) || defined(__GNUC__) - #ifndef __cplusplus - intmap = NULL; - hmput(intmap, 15, 7); - hmput(intmap, 11, 3); - hmput(intmap, 9, 5); - STBDS_ASSERT(hmget(intmap, 9) == 5); - STBDS_ASSERT(hmget(intmap, 11) == 3); - STBDS_ASSERT(hmget(intmap, 15) == 7); - #endif - #endif - - for (i=0; i < testsize; ++i) - stralloc(&sa, strkey(i)); - strreset(&sa); - - { - s.key = "a", s.value = 1; - shputs(strmap, s); - STBDS_ASSERT(*strmap[0].key == 'a'); - STBDS_ASSERT(strmap[0].key == s.key); - STBDS_ASSERT(strmap[0].value == s.value); - shfree(strmap); - } - - { - s.key = "a", s.value = 1; - sh_new_strdup(strmap); - shputs(strmap, s); - STBDS_ASSERT(*strmap[0].key == 'a'); - STBDS_ASSERT(strmap[0].key != s.key); - STBDS_ASSERT(strmap[0].value == s.value); - shfree(strmap); - } - - { - s.key = "a", s.value = 1; - sh_new_arena(strmap); - shputs(strmap, s); - STBDS_ASSERT(*strmap[0].key == 'a'); - STBDS_ASSERT(strmap[0].key != s.key); - STBDS_ASSERT(strmap[0].value == s.value); - shfree(strmap); - } - - for (j=0; j < 2; ++j) { - STBDS_ASSERT(shgeti(strmap,"foo") == -1); - if (j == 0) - sh_new_strdup(strmap); - else - sh_new_arena(strmap); - STBDS_ASSERT(shgeti(strmap,"foo") == -1); - shdefault(strmap, -2); - STBDS_ASSERT(shgeti(strmap,"foo") == -1); - for (i=0; i < testsize; i+=2) - shput(strmap, strkey(i), i*3); - for (i=0; i < testsize; i+=1) - if (i & 1) STBDS_ASSERT(shget(strmap, strkey(i)) == -2 ); - else STBDS_ASSERT(shget(strmap, strkey(i)) == i*3); - for (i=2; i < testsize; i+=4) - shdel(strmap, strkey(i)); // delete half the entries - for (i=0; i < testsize; i+=1) - if (i & 3) STBDS_ASSERT(shget(strmap, strkey(i)) == -2 ); - else STBDS_ASSERT(shget(strmap, strkey(i)) == i*3); - for (i=0; i < testsize; i+=1) - shdel(strmap, strkey(i)); // delete the rest of the entries - for (i=0; i < testsize; i+=1) - STBDS_ASSERT(shget(strmap, strkey(i)) == -2 ); - shfree(strmap); - } - - { - struct { char *key; char value; } *hash = NULL; - char name[4] = "jen"; - shput(hash, "bob" , 'h'); - shput(hash, "sally" , 'e'); - shput(hash, "fred" , 'l'); - shput(hash, "jen" , 'x'); - shput(hash, "doug" , 'o'); - - shput(hash, name , 'l'); - shfree(hash); - } - - for (i=0; i < testsize; i += 2) { - stbds_struct s = { i,i*2,i*3,i*4 }; - hmput(map, s, i*5); - } - - for (i=0; i < testsize; i += 1) { - stbds_struct s = { i,i*2,i*3 ,i*4 }; - stbds_struct t = { i,i*2,i*3+1,i*4 }; - if (i & 1) STBDS_ASSERT(hmget(map, s) == 0); - else STBDS_ASSERT(hmget(map, s) == i*5); - if (i & 1) STBDS_ASSERT(hmget_ts(map, s, temp) == 0); - else STBDS_ASSERT(hmget_ts(map, s, temp) == i*5); - //STBDS_ASSERT(hmget(map, t.key) == 0); - } - - for (i=0; i < testsize; i += 2) { - stbds_struct s = { i,i*2,i*3,i*4 }; - hmputs(map2, s); - } - hmfree(map); - - for (i=0; i < testsize; i += 1) { - stbds_struct s = { i,i*2,i*3,i*4 }; - stbds_struct t = { i,i*2,i*3+1,i*4 }; - if (i & 1) STBDS_ASSERT(hmgets(map2, s.key).d == 0); - else STBDS_ASSERT(hmgets(map2, s.key).d == i*4); - //STBDS_ASSERT(hmgetp(map2, t.key) == 0); - } - hmfree(map2); - - for (i=0; i < testsize; i += 2) { - stbds_struct2 s = { { i,i*2 }, i*3,i*4, i*5 }; - hmputs(map3, s); - } - for (i=0; i < testsize; i += 1) { - stbds_struct2 s = { { i,i*2}, i*3, i*4, i*5 }; - stbds_struct2 t = { { i,i*2}, i*3+1, i*4, i*5 }; - if (i & 1) STBDS_ASSERT(hmgets(map3, s.key).d == 0); - else STBDS_ASSERT(hmgets(map3, s.key).d == i*5); - //STBDS_ASSERT(hmgetp(map3, t.key) == 0); - } -#endif -} -#endif - - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2019 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, -commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to -this software under copyright law. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------- -*/ diff --git a/CMakeLists.txt b/CMakeLists.txt index b22b369..87e68c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ option(KALMIA_BUILD_TESTS "Build the tests" ON) option(KALMIA_BUILD_EXAMPLE "Build the example" ON) add_library(kalmia STATIC) -target_include_directories(kalmia PUBLIC include 3rdparty 3rdparty/ezxml) +target_include_directories(kalmia PUBLIC include) if (UNIX) set_target_properties( kalmia PROPERTIES @@ -34,4 +34,3 @@ if (KALMIA_BUILD_EXAMPLE) endif() add_subdirectory(src) -add_subdirectory(3rdparty/ezxml) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d0589ed..6ad8ede 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,6 @@ project(kalmia) target_include_directories(kalmia PUBLIC ${CMAKE_CURRENT_LIST_DIR}) -target_link_libraries(kalmia ezxml) if (KALMIA_BUILD_TESTS) target_sources( @@ -12,3 +11,4 @@ endif() add_subdirectory(util) add_subdirectory(geometry) +add_subdirectory(xml) diff --git a/src/geometry/geometry.c b/src/geometry/geometry.c index 7046f1e..ba1ca58 100644 --- a/src/geometry/geometry.c +++ b/src/geometry/geometry.c @@ -1,41 +1,5 @@ #include <string.h> #include <kalmia.h> -#include <ezxml.h> #include "util/util.h" #include "geometry.h" - - -int kai_parse_float_array(struct ka_float_array_t *dest, ezxml_t src) -{ - /* get count */ - const char *count = ezxml_attr(src, "count"); - if (count == NULL) { - fprintf(stderr, "[kalmia] ERROR: required \"count\" parameter not present for float_array\n"); - return -1; - } - char *end; - dest->count = strtol(count, &end, 10); - - /* get id, if present */ - const char *id = ezxml_attr(src, "id"); - if (id != NULL) { - size_t id_len = strlen(id) + 1; - dest->id = kai_alloc(sizeof(char) * id_len, "float_array id"); - if (dest->id == NULL) { - return -1; - } - strncpy(dest->id, id, id_len); - } - else { - dest->id = NULL; - } - - /* parse floats */ - dest->data = kai_alloc(sizeof(ka_real_t) * dest->count, "float_array data"); - if (dest->data == NULL) { - free(dest->id); - return -1; - } - kai_text_to_reals(dest->data, ezxml_txt(src), dest->count); -} diff --git a/src/geometry/geometry.h b/src/geometry/geometry.h index 6268e3b..da089c1 100644 --- a/src/geometry/geometry.h +++ b/src/geometry/geometry.h @@ -2,8 +2,5 @@ #define KALMIA_GEOMETRY_H #include <kalmia.h> -#include <ezxml.h> - -int kai_parse_float_array(struct ka_float_array_t *dest, ezxml_t src); #endif diff --git a/src/geometry/geometry.test.c b/src/geometry/geometry.test.c index bb06aeb..fe4421e 100644 --- a/src/geometry/geometry.test.c +++ b/src/geometry/geometry.test.c @@ -1,7 +1,6 @@ #include <string.h> #include <kalmia.h> -#include <ezxml.h> #include "geometry.h" #include "test/test.h" @@ -9,34 +8,5 @@ LILY_FILE_BEGIN(geometry_suite) -LILY_TEST("parse float array") -{ - char str[1024]; - strncpy( - str, - "<float_array id=\"sequence\" count=\"5\">\n" - " -0.5 -0.25 0 0.25 0.5\n" - "</float_array>", - 1024 - ); - - ezxml_t tag = ezxml_parse_str(str, strlen(str)+1); - - struct ka_float_array_t float_array; - kai_parse_float_array(&float_array, tag); - - CHECK_EQS(float_array.id, "sequence"); - REQUIRE_EQ(float_array.count, 5, "%ul"); - REQUIRE_NEQ(float_array.data, NULL, "%p"); - - CHECK_EQ(float_array.data[0], -0.50, "%f"); - CHECK_EQ(float_array.data[1], -0.25, "%f"); - CHECK_EQ(float_array.data[2], 0.00, "%f"); - CHECK_EQ(float_array.data[3], 0.25, "%f"); - CHECK_EQ(float_array.data[4], 0.50, "%f"); -} -#include LILY_PUSH_TEST() - - #define LILY_FILE_END #include LILY_REGISTER_TESTS() diff --git a/src/xml/CMakeLists.txt b/src/xml/CMakeLists.txt new file mode 100644 index 0000000..9790692 --- /dev/null +++ b/src/xml/CMakeLists.txt @@ -0,0 +1,7 @@ +project(kalmia) + +target_sources(kalmia PUBLIC + kalmia.tab.c + kalmia.lex.c + xml.c +) diff --git a/src/xml/kalmia.lex.c b/src/xml/kalmia.lex.c new file mode 100644 index 0000000..1862064 --- /dev/null +++ b/src/xml/kalmia.lex.c @@ -0,0 +1,2343 @@ +#line 1 "kalmia.lex.c" + +#line 3 "kalmia.lex.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +#ifdef yy_create_buffer +#define kalmia_create_buffer_ALREADY_DEFINED +#else +#define yy_create_buffer kalmia_create_buffer +#endif + +#ifdef yy_delete_buffer +#define kalmia_delete_buffer_ALREADY_DEFINED +#else +#define yy_delete_buffer kalmia_delete_buffer +#endif + +#ifdef yy_scan_buffer +#define kalmia_scan_buffer_ALREADY_DEFINED +#else +#define yy_scan_buffer kalmia_scan_buffer +#endif + +#ifdef yy_scan_string +#define kalmia_scan_string_ALREADY_DEFINED +#else +#define yy_scan_string kalmia_scan_string +#endif + +#ifdef yy_scan_bytes +#define kalmia_scan_bytes_ALREADY_DEFINED +#else +#define yy_scan_bytes kalmia_scan_bytes +#endif + +#ifdef yy_init_buffer +#define kalmia_init_buffer_ALREADY_DEFINED +#else +#define yy_init_buffer kalmia_init_buffer +#endif + +#ifdef yy_flush_buffer +#define kalmia_flush_buffer_ALREADY_DEFINED +#else +#define yy_flush_buffer kalmia_flush_buffer +#endif + +#ifdef yy_load_buffer_state +#define kalmia_load_buffer_state_ALREADY_DEFINED +#else +#define yy_load_buffer_state kalmia_load_buffer_state +#endif + +#ifdef yy_switch_to_buffer +#define kalmia_switch_to_buffer_ALREADY_DEFINED +#else +#define yy_switch_to_buffer kalmia_switch_to_buffer +#endif + +#ifdef yypush_buffer_state +#define kalmiapush_buffer_state_ALREADY_DEFINED +#else +#define yypush_buffer_state kalmiapush_buffer_state +#endif + +#ifdef yypop_buffer_state +#define kalmiapop_buffer_state_ALREADY_DEFINED +#else +#define yypop_buffer_state kalmiapop_buffer_state +#endif + +#ifdef yyensure_buffer_stack +#define kalmiaensure_buffer_stack_ALREADY_DEFINED +#else +#define yyensure_buffer_stack kalmiaensure_buffer_stack +#endif + +#ifdef yylex +#define kalmialex_ALREADY_DEFINED +#else +#define yylex kalmialex +#endif + +#ifdef yyrestart +#define kalmiarestart_ALREADY_DEFINED +#else +#define yyrestart kalmiarestart +#endif + +#ifdef yylex_init +#define kalmialex_init_ALREADY_DEFINED +#else +#define yylex_init kalmialex_init +#endif + +#ifdef yylex_init_extra +#define kalmialex_init_extra_ALREADY_DEFINED +#else +#define yylex_init_extra kalmialex_init_extra +#endif + +#ifdef yylex_destroy +#define kalmialex_destroy_ALREADY_DEFINED +#else +#define yylex_destroy kalmialex_destroy +#endif + +#ifdef yyget_debug +#define kalmiaget_debug_ALREADY_DEFINED +#else +#define yyget_debug kalmiaget_debug +#endif + +#ifdef yyset_debug +#define kalmiaset_debug_ALREADY_DEFINED +#else +#define yyset_debug kalmiaset_debug +#endif + +#ifdef yyget_extra +#define kalmiaget_extra_ALREADY_DEFINED +#else +#define yyget_extra kalmiaget_extra +#endif + +#ifdef yyset_extra +#define kalmiaset_extra_ALREADY_DEFINED +#else +#define yyset_extra kalmiaset_extra +#endif + +#ifdef yyget_in +#define kalmiaget_in_ALREADY_DEFINED +#else +#define yyget_in kalmiaget_in +#endif + +#ifdef yyset_in +#define kalmiaset_in_ALREADY_DEFINED +#else +#define yyset_in kalmiaset_in +#endif + +#ifdef yyget_out +#define kalmiaget_out_ALREADY_DEFINED +#else +#define yyget_out kalmiaget_out +#endif + +#ifdef yyset_out +#define kalmiaset_out_ALREADY_DEFINED +#else +#define yyset_out kalmiaset_out +#endif + +#ifdef yyget_leng +#define kalmiaget_leng_ALREADY_DEFINED +#else +#define yyget_leng kalmiaget_leng +#endif + +#ifdef yyget_text +#define kalmiaget_text_ALREADY_DEFINED +#else +#define yyget_text kalmiaget_text +#endif + +#ifdef yyget_lineno +#define kalmiaget_lineno_ALREADY_DEFINED +#else +#define yyget_lineno kalmiaget_lineno +#endif + +#ifdef yyset_lineno +#define kalmiaset_lineno_ALREADY_DEFINED +#else +#define yyset_lineno kalmiaset_lineno +#endif + +#ifdef yyget_column +#define kalmiaget_column_ALREADY_DEFINED +#else +#define yyget_column kalmiaget_column +#endif + +#ifdef yyset_column +#define kalmiaset_column_ALREADY_DEFINED +#else +#define yyset_column kalmiaset_column +#endif + +#ifdef yywrap +#define kalmiawrap_ALREADY_DEFINED +#else +#define yywrap kalmiawrap +#endif + +#ifdef yyget_lval +#define kalmiaget_lval_ALREADY_DEFINED +#else +#define yyget_lval kalmiaget_lval +#endif + +#ifdef yyset_lval +#define kalmiaset_lval_ALREADY_DEFINED +#else +#define yyset_lval kalmiaset_lval +#endif + +#ifdef yyget_lloc +#define kalmiaget_lloc_ALREADY_DEFINED +#else +#define yyget_lloc kalmiaget_lloc +#endif + +#ifdef yyset_lloc +#define kalmiaset_lloc_ALREADY_DEFINED +#else +#define yyset_lloc kalmiaset_lloc +#endif + +#ifdef yyalloc +#define kalmiaalloc_ALREADY_DEFINED +#else +#define yyalloc kalmiaalloc +#endif + +#ifdef yyrealloc +#define kalmiarealloc_ALREADY_DEFINED +#else +#define yyrealloc kalmiarealloc +#endif + +#ifdef yyfree +#define kalmiafree_ALREADY_DEFINED +#else +#define yyfree kalmiafree +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin , yyscanner ) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + #define YY_LINENO_REWIND_TO(ptr) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void yyrestart ( FILE *input_file , yyscan_t yyscanner ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); +void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +void yypop_buffer_state ( yyscan_t yyscanner ); + +static void yyensure_buffer_stack ( yyscan_t yyscanner ); +static void yy_load_buffer_state ( yyscan_t yyscanner ); +static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); +#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner) + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); + +void *yyalloc ( yy_size_t , yyscan_t yyscanner ); +void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); +void yyfree ( void * , yyscan_t yyscanner ); + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +#define kalmiawrap(yyscanner) (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP +typedef flex_uint8_t YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); +static int yy_get_next_buffer ( yyscan_t yyscanner ); +static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; +#define YY_NUM_RULES 15 +#define YY_END_OF_BUFFER 16 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_acclist[32] = + { 0, + 16, 15, 2, 15, 4, 15, 13, 15, 12, 15, + 15, 3, 15, 11, 15, 15, 8, 15,16393, 10, + 15, 6, 15, 14, 5, 13, 7, 8,16393, 8201, + 1 + } ; + +static const flex_int16_t yy_accept[37] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 2, 3, 5, + 7, 9, 11, 12, 14, 16, 17, 20, 22, 24, + 25, 25, 26, 26, 27, 28, 28, 30, 31, 31, + 31, 31, 31, 31, 32, 32 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 4, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 5, 5, 6, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 7, 1, 8, + 9, 10, 11, 1, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 1, 1, 1, 1, 7, 1, 7, 7, 7, 7, + + 7, 7, 7, 7, 7, 7, 7, 12, 13, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 14, + 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static const YY_CHAR yy_meta[15] = + { 0, + 1, 2, 3, 4, 5, 1, 5, 6, 2, 1, + 1, 5, 5, 5 + } ; + +static const flex_int16_t yy_base[43] = + { 0, + 0, 7, 77, 73, 15, 0, 71, 2, 82, 0, + 0, 82, 82, 82, 82, 56, 28, 82, 82, 10, + 30, 82, 30, 0, 82, 34, 36, 82, 29, 29, + 29, 25, 24, 3, 82, 45, 51, 57, 62, 67, + 71, 74 + } ; + +static const flex_int16_t yy_def[43] = + { 0, + 36, 36, 37, 37, 35, 5, 35, 38, 35, 35, + 39, 35, 35, 35, 35, 35, 40, 35, 35, 38, + 38, 35, 35, 39, 35, 41, 40, 35, 35, 35, + 42, 42, 42, 42, 0, 35, 35, 35, 35, 35, + 35, 35 + } ; + +static const flex_int16_t yy_nxt[97] = + { 0, + 35, 9, 9, 21, 21, 22, 35, 10, 9, 9, + 23, 21, 21, 33, 10, 13, 14, 14, 15, 13, + 16, 17, 13, 18, 19, 13, 17, 17, 17, 26, + 26, 21, 21, 34, 33, 33, 28, 26, 26, 33, + 31, 30, 28, 29, 28, 8, 8, 8, 8, 8, + 8, 11, 11, 11, 11, 11, 11, 20, 20, 20, + 20, 20, 24, 24, 24, 25, 24, 24, 27, 27, + 35, 27, 26, 26, 32, 32, 12, 32, 32, 32, + 12, 7, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35 + + } ; + +static const flex_int16_t yy_chk[97] = + { 0, + 0, 1, 1, 8, 8, 10, 0, 1, 2, 2, + 10, 20, 20, 34, 2, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 17, + 17, 21, 21, 33, 33, 32, 17, 27, 27, 31, + 30, 29, 26, 23, 27, 36, 36, 36, 36, 36, + 36, 37, 37, 37, 37, 37, 37, 38, 38, 38, + 38, 38, 39, 39, 39, 16, 39, 39, 40, 40, + 7, 40, 41, 41, 42, 42, 4, 42, 42, 42, + 3, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35 + + } ; + +#define YY_TRAILING_MASK 0x2000 +#define YY_TRAILING_HEAD_MASK 0x4000 +#define REJECT \ +{ \ +*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ \ +yy_cp = yyg->yy_full_match; /* restore poss. backed-over text */ \ +yyg->yy_lp = yyg->yy_full_lp; /* restore orig. accepting pos. */ \ +yyg->yy_state_ptr = yyg->yy_full_state; /* restore orig. state */ \ +yy_current_state = *yyg->yy_state_ptr; /* restore curr. state */ \ +++yyg->yy_lp; \ +goto find_rule; \ +} + +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "kalmia.l" +#define YY_NO_INPUT 1 + +#line 7 "kalmia.l" +#include <string.h> +#define YYLTYPE KALMIALTYPE +#define YYSTYPE KALMIASTYPE +#include "kalmia.tab.h" +#define YY_USER_ACTION \ + yylloc->first_line = yylloc->last_line; \ + yylloc->first_column = yylloc->last_column; \ + if (*yytext == '\n') { \ + yylloc->last_line += 1; \ + yylloc->last_column = 0; \ + } \ + else { \ + yylloc->last_column += yyleng; \ + } +#line 719 "kalmia.lex.c" +#line 720 "kalmia.lex.c" + +#define INITIAL 0 +#define STRING 1 +#define TAG 2 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include <unistd.h> +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + yy_state_type *yy_state_buf; + yy_state_type *yy_state_ptr; + char *yy_full_match; + int yy_lp; + + /* These are only needed for trailing context rules, + * but there's no conditional variable for that yet. */ + int yy_looking_for_trail_begin; + int yy_full_lp; + int *yy_full_state; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + YYSTYPE * yylval_r; + + YYLTYPE * yylloc_r; + + }; /* end struct yyguts_t */ + +static int yy_init_globals ( yyscan_t yyscanner ); + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define yylval yyg->yylval_r + + # define yylloc yyg->yylloc_r + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( yyscan_t yyscanner ); + +int yyget_debug ( yyscan_t yyscanner ); + +void yyset_debug ( int debug_flag , yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); + +FILE *yyget_in ( yyscan_t yyscanner ); + +void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); + +FILE *yyget_out ( yyscan_t yyscanner ); + +void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); + + int yyget_leng ( yyscan_t yyscanner ); + +char *yyget_text ( yyscan_t yyscanner ); + +int yyget_lineno ( yyscan_t yyscanner ); + +void yyset_lineno ( int _line_number , yyscan_t yyscanner ); + +int yyget_column ( yyscan_t yyscanner ); + +void yyset_column ( int _column_no , yyscan_t yyscanner ); + +YYSTYPE * yyget_lval ( yyscan_t yyscanner ); + +void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner ); + + YYLTYPE *yyget_lloc ( yyscan_t yyscanner ); + + void yyset_lloc ( YYLTYPE * yylloc_param , yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( yyscan_t yyscanner ); +#else +extern int yywrap ( yyscan_t yyscanner ); +#endif +#endif + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * , yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput ( yyscan_t yyscanner ); +#else +static int input ( yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex \ + (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner); + +#define YY_DECL int yylex \ + (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yylval = yylval_param; + + yylloc = yylloc_param; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + /* Create the reject buffer large enough to save one state per allowed character. */ + if ( ! yyg->yy_state_buf ) + yyg->yy_state_buf = (yy_state_type *)yyalloc(YY_STATE_BUF_SIZE , yyscanner); + if ( ! yyg->yy_state_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yylex()" ); + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_load_buffer_state( yyscanner ); + } + + { +#line 29 "kalmia.l" + + + +#line 1025 "kalmia.lex.c" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; + + yyg->yy_state_ptr = yyg->yy_state_buf; + *yyg->yy_state_ptr++ = yy_current_state; + +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 36 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + *yyg->yy_state_ptr++ = yy_current_state; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 82 ); + +yy_find_action: + yy_current_state = *--yyg->yy_state_ptr; + yyg->yy_lp = yy_accept[yy_current_state]; +find_rule: /* we branch to this label when backing up */ + for ( ; ; ) /* until we find what rule we matched */ + { + if ( yyg->yy_lp && yyg->yy_lp < yy_accept[yy_current_state + 1] ) + { + yy_act = yy_acclist[yyg->yy_lp]; + if ( yy_act & YY_TRAILING_HEAD_MASK || + yyg->yy_looking_for_trail_begin ) + { + if ( yy_act == yyg->yy_looking_for_trail_begin ) + { + yyg->yy_looking_for_trail_begin = 0; + yy_act &= ~YY_TRAILING_HEAD_MASK; + break; + } + } + else if ( yy_act & YY_TRAILING_MASK ) + { + yyg->yy_looking_for_trail_begin = yy_act & ~YY_TRAILING_MASK; + yyg->yy_looking_for_trail_begin |= YY_TRAILING_HEAD_MASK; + } + else + { + yyg->yy_full_match = yy_cp; + yyg->yy_full_state = yyg->yy_state_ptr; + yyg->yy_full_lp = yyg->yy_lp; + break; + } + ++yyg->yy_lp; + goto find_rule; + } + --yy_cp; + yy_current_state = *--yyg->yy_state_ptr; + yyg->yy_lp = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ +case 1: +YY_RULE_SETUP +#line 32 "kalmia.l" +{ + /* xml prologue */ + return PROLOG; +} + YY_BREAK +case 2: +/* rule 2 can match eol */ +#line 37 "kalmia.l" +case 3: +/* rule 3 can match eol */ +YY_RULE_SETUP +#line 37 "kalmia.l" +{ + /* ignore whitespace */ +} + YY_BREAK +case 4: +YY_RULE_SETUP +#line 42 "kalmia.l" +{ BEGIN(TAG); return S_TAG_OPEN; } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 43 "kalmia.l" +{ BEGIN(TAG); return E_TAG_OPEN; } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 44 "kalmia.l" +{ BEGIN(INITIAL); return TAG_CLOSE; } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 45 "kalmia.l" +{ BEGIN(INITIAL); return EMPTY_TAG_CLOSE; } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 48 "kalmia.l" +{ + /* generic tag name */ + yylval->string = strdup(yytext); + return NAME; +} + YY_BREAK +case 9: +/* rule 9 can match eol */ +YY_RULE_SETUP +#line 53 "kalmia.l" +{ + /* generic attribute key */ + yylval->string = strdup(yytext); + return ATTR; +} + YY_BREAK +case 10: +YY_RULE_SETUP +#line 58 "kalmia.l" +{ + /* attribute "=" */ + return *yytext; +} + YY_BREAK +case 11: +YY_RULE_SETUP +#line 64 "kalmia.l" +{ + /* begin a string */ + BEGIN(STRING); + return *yytext; +} + YY_BREAK +case 12: +YY_RULE_SETUP +#line 69 "kalmia.l" +{ + /* end a string */ + BEGIN(TAG); + return *yytext; +} + YY_BREAK +case 13: +/* rule 13 can match eol */ +YY_RULE_SETUP +#line 74 "kalmia.l" +{ + /* within a string */ + yylval->string = strdup(yytext); + return TEXT; +} + YY_BREAK +case 14: +/* rule 14 can match eol */ +YY_RULE_SETUP +#line 81 "kalmia.l" +{ + yylval->string = strdup(yytext); + return CONTENT; +} + YY_BREAK +case 15: +YY_RULE_SETUP +#line 85 "kalmia.l" +YY_FATAL_ERROR( "flex scanner jammed" ); + YY_BREAK +#line 1213 "kalmia.lex.c" + case YY_STATE_EOF(INITIAL): + case YY_STATE_EOF(STRING): + case YY_STATE_EOF(TAG): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( yywrap( yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin , yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + yy_state_type yy_current_state; + char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + yyg->yy_state_ptr = yyg->yy_state_buf; + *yyg->yy_state_ptr++ = yy_current_state; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 36 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + *yyg->yy_state_ptr++ = yy_current_state; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + + YY_CHAR yy_c = 1; + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 36 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 35); + if ( ! yy_is_jam ) + *yyg->yy_state_ptr++ = yy_current_state; + + (void)yyg; + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin , yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( yyscanner ) ) + return 0; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner); + yy_load_buffer_state( yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void yy_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file , yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * @param yyscanner The scanner object. + */ + void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree( (void *) b->yy_ch_buf , yyscanner ); + + yyfree( (void *) b , yyscanner ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_flush_buffer( b , yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(yyscanner); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void yypop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (yyscan_t yyscanner) +{ + yy_size_t num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b , yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) +{ + + return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) yyalloc( n , yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n , yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param _line_number line number + * @param yyscanner The scanner object. + */ +void yyset_lineno (int _line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); + + yylineno = _line_number; +} + +/** Set the current column. + * @param _column_no column number + * @param yyscanner The scanner object. + */ +void yyset_column (int _column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_column called with no buffer" ); + + yycolumn = _column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * @param yyscanner The scanner object. + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = _out_str ; +} + +int yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void yyset_debug (int _bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = _bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +YYSTYPE * yyget_lval (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylval; +} + +void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylval = yylval_param; +} + +YYLTYPE *yyget_lloc (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylloc; +} + +void yyset_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylloc = yylloc_param; +} + +/* User-visible API */ + +/* yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ +int yylex_init(yyscan_t* ptr_yy_globals) +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* yylex_init_extra has the same functionality as yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to yyalloc in + * the yyextra field. + */ +int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals ) +{ + struct yyguts_t dummy_yyguts; + + yyset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + yyset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = NULL; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = NULL; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + + yyg->yy_state_buf = 0; + yyg->yy_state_ptr = 0; + yyg->yy_full_match = 0; + yyg->yy_lp = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + yyfree(yyg->yy_buffer_stack , yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + yyfree( yyg->yy_start_stack , yyscanner ); + yyg->yy_start_stack = NULL; + + yyfree ( yyg->yy_state_buf , yyscanner); + yyg->yy_state_buf = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s , yyscan_t yyscanner) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + return malloc(size); +} + +void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void yyfree (void * ptr , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 85 "kalmia.l" diff --git a/src/xml/kalmia.lex.h b/src/xml/kalmia.lex.h new file mode 100644 index 0000000..ad35689 --- /dev/null +++ b/src/xml/kalmia.lex.h @@ -0,0 +1,735 @@ +#ifndef kalmiaHEADER_H +#define kalmiaHEADER_H 1 +#define kalmiaIN_HEADER 1 + +#line 5 "kalmia.lex.h" + +#line 7 "kalmia.lex.h" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +#ifdef yy_create_buffer +#define kalmia_create_buffer_ALREADY_DEFINED +#else +#define yy_create_buffer kalmia_create_buffer +#endif + +#ifdef yy_delete_buffer +#define kalmia_delete_buffer_ALREADY_DEFINED +#else +#define yy_delete_buffer kalmia_delete_buffer +#endif + +#ifdef yy_scan_buffer +#define kalmia_scan_buffer_ALREADY_DEFINED +#else +#define yy_scan_buffer kalmia_scan_buffer +#endif + +#ifdef yy_scan_string +#define kalmia_scan_string_ALREADY_DEFINED +#else +#define yy_scan_string kalmia_scan_string +#endif + +#ifdef yy_scan_bytes +#define kalmia_scan_bytes_ALREADY_DEFINED +#else +#define yy_scan_bytes kalmia_scan_bytes +#endif + +#ifdef yy_init_buffer +#define kalmia_init_buffer_ALREADY_DEFINED +#else +#define yy_init_buffer kalmia_init_buffer +#endif + +#ifdef yy_flush_buffer +#define kalmia_flush_buffer_ALREADY_DEFINED +#else +#define yy_flush_buffer kalmia_flush_buffer +#endif + +#ifdef yy_load_buffer_state +#define kalmia_load_buffer_state_ALREADY_DEFINED +#else +#define yy_load_buffer_state kalmia_load_buffer_state +#endif + +#ifdef yy_switch_to_buffer +#define kalmia_switch_to_buffer_ALREADY_DEFINED +#else +#define yy_switch_to_buffer kalmia_switch_to_buffer +#endif + +#ifdef yypush_buffer_state +#define kalmiapush_buffer_state_ALREADY_DEFINED +#else +#define yypush_buffer_state kalmiapush_buffer_state +#endif + +#ifdef yypop_buffer_state +#define kalmiapop_buffer_state_ALREADY_DEFINED +#else +#define yypop_buffer_state kalmiapop_buffer_state +#endif + +#ifdef yyensure_buffer_stack +#define kalmiaensure_buffer_stack_ALREADY_DEFINED +#else +#define yyensure_buffer_stack kalmiaensure_buffer_stack +#endif + +#ifdef yylex +#define kalmialex_ALREADY_DEFINED +#else +#define yylex kalmialex +#endif + +#ifdef yyrestart +#define kalmiarestart_ALREADY_DEFINED +#else +#define yyrestart kalmiarestart +#endif + +#ifdef yylex_init +#define kalmialex_init_ALREADY_DEFINED +#else +#define yylex_init kalmialex_init +#endif + +#ifdef yylex_init_extra +#define kalmialex_init_extra_ALREADY_DEFINED +#else +#define yylex_init_extra kalmialex_init_extra +#endif + +#ifdef yylex_destroy +#define kalmialex_destroy_ALREADY_DEFINED +#else +#define yylex_destroy kalmialex_destroy +#endif + +#ifdef yyget_debug +#define kalmiaget_debug_ALREADY_DEFINED +#else +#define yyget_debug kalmiaget_debug +#endif + +#ifdef yyset_debug +#define kalmiaset_debug_ALREADY_DEFINED +#else +#define yyset_debug kalmiaset_debug +#endif + +#ifdef yyget_extra +#define kalmiaget_extra_ALREADY_DEFINED +#else +#define yyget_extra kalmiaget_extra +#endif + +#ifdef yyset_extra +#define kalmiaset_extra_ALREADY_DEFINED +#else +#define yyset_extra kalmiaset_extra +#endif + +#ifdef yyget_in +#define kalmiaget_in_ALREADY_DEFINED +#else +#define yyget_in kalmiaget_in +#endif + +#ifdef yyset_in +#define kalmiaset_in_ALREADY_DEFINED +#else +#define yyset_in kalmiaset_in +#endif + +#ifdef yyget_out +#define kalmiaget_out_ALREADY_DEFINED +#else +#define yyget_out kalmiaget_out +#endif + +#ifdef yyset_out +#define kalmiaset_out_ALREADY_DEFINED +#else +#define yyset_out kalmiaset_out +#endif + +#ifdef yyget_leng +#define kalmiaget_leng_ALREADY_DEFINED +#else +#define yyget_leng kalmiaget_leng +#endif + +#ifdef yyget_text +#define kalmiaget_text_ALREADY_DEFINED +#else +#define yyget_text kalmiaget_text +#endif + +#ifdef yyget_lineno +#define kalmiaget_lineno_ALREADY_DEFINED +#else +#define yyget_lineno kalmiaget_lineno +#endif + +#ifdef yyset_lineno +#define kalmiaset_lineno_ALREADY_DEFINED +#else +#define yyset_lineno kalmiaset_lineno +#endif + +#ifdef yyget_column +#define kalmiaget_column_ALREADY_DEFINED +#else +#define yyget_column kalmiaget_column +#endif + +#ifdef yyset_column +#define kalmiaset_column_ALREADY_DEFINED +#else +#define yyset_column kalmiaset_column +#endif + +#ifdef yywrap +#define kalmiawrap_ALREADY_DEFINED +#else +#define yywrap kalmiawrap +#endif + +#ifdef yyget_lval +#define kalmiaget_lval_ALREADY_DEFINED +#else +#define yyget_lval kalmiaget_lval +#endif + +#ifdef yyset_lval +#define kalmiaset_lval_ALREADY_DEFINED +#else +#define yyset_lval kalmiaset_lval +#endif + +#ifdef yyget_lloc +#define kalmiaget_lloc_ALREADY_DEFINED +#else +#define yyget_lloc kalmiaget_lloc +#endif + +#ifdef yyset_lloc +#define kalmiaset_lloc_ALREADY_DEFINED +#else +#define yyset_lloc kalmiaset_lloc +#endif + +#ifdef yyalloc +#define kalmiaalloc_ALREADY_DEFINED +#else +#define yyalloc kalmiaalloc +#endif + +#ifdef yyrealloc +#define kalmiarealloc_ALREADY_DEFINED +#else +#define yyrealloc kalmiarealloc +#endif + +#ifdef yyfree +#define kalmiafree_ALREADY_DEFINED +#else +#define yyfree kalmiafree +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +void yyrestart ( FILE *input_file , yyscan_t yyscanner ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); +void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +void yypop_buffer_state ( yyscan_t yyscanner ); + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); + +void *yyalloc ( yy_size_t , yyscan_t yyscanner ); +void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); +void yyfree ( void * , yyscan_t yyscanner ); + +#define kalmiawrap(yyscanner) (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP + +#define yytext_ptr yytext_r + +#ifdef YY_HEADER_EXPORT_START_CONDITIONS +#define INITIAL 0 +#define STRING 1 +#define TAG 2 + +#endif + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include <unistd.h> +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( yyscan_t yyscanner ); + +int yyget_debug ( yyscan_t yyscanner ); + +void yyset_debug ( int debug_flag , yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); + +FILE *yyget_in ( yyscan_t yyscanner ); + +void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); + +FILE *yyget_out ( yyscan_t yyscanner ); + +void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); + + int yyget_leng ( yyscan_t yyscanner ); + +char *yyget_text ( yyscan_t yyscanner ); + +int yyget_lineno ( yyscan_t yyscanner ); + +void yyset_lineno ( int _line_number , yyscan_t yyscanner ); + +int yyget_column ( yyscan_t yyscanner ); + +void yyset_column ( int _column_no , yyscan_t yyscanner ); + +YYSTYPE * yyget_lval ( yyscan_t yyscanner ); + +void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner ); + + YYLTYPE *yyget_lloc ( yyscan_t yyscanner ); + + void yyset_lloc ( YYLTYPE * yylloc_param , yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( yyscan_t yyscanner ); +#else +extern int yywrap ( yyscan_t yyscanner ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * , yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex \ + (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner); + +#define YY_DECL int yylex \ + (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +#undef YY_NEW_FILE +#undef YY_FLUSH_BUFFER +#undef yy_set_bol +#undef yy_new_buffer +#undef yy_set_interactive +#undef YY_DO_BEFORE_ACTION + +#ifdef YY_DECL_IS_OURS +#undef YY_DECL_IS_OURS +#undef YY_DECL +#endif + +#ifndef kalmia_create_buffer_ALREADY_DEFINED +#undef yy_create_buffer +#endif +#ifndef kalmia_delete_buffer_ALREADY_DEFINED +#undef yy_delete_buffer +#endif +#ifndef kalmia_scan_buffer_ALREADY_DEFINED +#undef yy_scan_buffer +#endif +#ifndef kalmia_scan_string_ALREADY_DEFINED +#undef yy_scan_string +#endif +#ifndef kalmia_scan_bytes_ALREADY_DEFINED +#undef yy_scan_bytes +#endif +#ifndef kalmia_init_buffer_ALREADY_DEFINED +#undef yy_init_buffer +#endif +#ifndef kalmia_flush_buffer_ALREADY_DEFINED +#undef yy_flush_buffer +#endif +#ifndef kalmia_load_buffer_state_ALREADY_DEFINED +#undef yy_load_buffer_state +#endif +#ifndef kalmia_switch_to_buffer_ALREADY_DEFINED +#undef yy_switch_to_buffer +#endif +#ifndef kalmiapush_buffer_state_ALREADY_DEFINED +#undef yypush_buffer_state +#endif +#ifndef kalmiapop_buffer_state_ALREADY_DEFINED +#undef yypop_buffer_state +#endif +#ifndef kalmiaensure_buffer_stack_ALREADY_DEFINED +#undef yyensure_buffer_stack +#endif +#ifndef kalmialex_ALREADY_DEFINED +#undef yylex +#endif +#ifndef kalmiarestart_ALREADY_DEFINED +#undef yyrestart +#endif +#ifndef kalmialex_init_ALREADY_DEFINED +#undef yylex_init +#endif +#ifndef kalmialex_init_extra_ALREADY_DEFINED +#undef yylex_init_extra +#endif +#ifndef kalmialex_destroy_ALREADY_DEFINED +#undef yylex_destroy +#endif +#ifndef kalmiaget_debug_ALREADY_DEFINED +#undef yyget_debug +#endif +#ifndef kalmiaset_debug_ALREADY_DEFINED +#undef yyset_debug +#endif +#ifndef kalmiaget_extra_ALREADY_DEFINED +#undef yyget_extra +#endif +#ifndef kalmiaset_extra_ALREADY_DEFINED +#undef yyset_extra +#endif +#ifndef kalmiaget_in_ALREADY_DEFINED +#undef yyget_in +#endif +#ifndef kalmiaset_in_ALREADY_DEFINED +#undef yyset_in +#endif +#ifndef kalmiaget_out_ALREADY_DEFINED +#undef yyget_out +#endif +#ifndef kalmiaset_out_ALREADY_DEFINED +#undef yyset_out +#endif +#ifndef kalmiaget_leng_ALREADY_DEFINED +#undef yyget_leng +#endif +#ifndef kalmiaget_text_ALREADY_DEFINED +#undef yyget_text +#endif +#ifndef kalmiaget_lineno_ALREADY_DEFINED +#undef yyget_lineno +#endif +#ifndef kalmiaset_lineno_ALREADY_DEFINED +#undef yyset_lineno +#endif +#ifndef kalmiaget_column_ALREADY_DEFINED +#undef yyget_column +#endif +#ifndef kalmiaset_column_ALREADY_DEFINED +#undef yyset_column +#endif +#ifndef kalmiawrap_ALREADY_DEFINED +#undef yywrap +#endif +#ifndef kalmiaget_lval_ALREADY_DEFINED +#undef yyget_lval +#endif +#ifndef kalmiaset_lval_ALREADY_DEFINED +#undef yyset_lval +#endif +#ifndef kalmiaget_lloc_ALREADY_DEFINED +#undef yyget_lloc +#endif +#ifndef kalmiaset_lloc_ALREADY_DEFINED +#undef yyset_lloc +#endif +#ifndef kalmiaalloc_ALREADY_DEFINED +#undef yyalloc +#endif +#ifndef kalmiarealloc_ALREADY_DEFINED +#undef yyrealloc +#endif +#ifndef kalmiafree_ALREADY_DEFINED +#undef yyfree +#endif +#ifndef kalmiatext_ALREADY_DEFINED +#undef yytext +#endif +#ifndef kalmialeng_ALREADY_DEFINED +#undef yyleng +#endif +#ifndef kalmiain_ALREADY_DEFINED +#undef yyin +#endif +#ifndef kalmiaout_ALREADY_DEFINED +#undef yyout +#endif +#ifndef kalmia_flex_debug_ALREADY_DEFINED +#undef yy_flex_debug +#endif +#ifndef kalmialineno_ALREADY_DEFINED +#undef yylineno +#endif +#ifndef kalmiatables_fload_ALREADY_DEFINED +#undef yytables_fload +#endif +#ifndef kalmiatables_destroy_ALREADY_DEFINED +#undef yytables_destroy +#endif +#ifndef kalmiaTABLES_NAME_ALREADY_DEFINED +#undef yyTABLES_NAME +#endif + +#line 85 "kalmia.l" + +#line 733 "kalmia.lex.h" +#undef kalmiaIN_HEADER +#endif /* kalmiaHEADER_H */ diff --git a/src/xml/kalmia.tab.c b/src/xml/kalmia.tab.c new file mode 100644 index 0000000..6f6f547 --- /dev/null +++ b/src/xml/kalmia.tab.c @@ -0,0 +1,2001 @@ +/* A Bison parser, made by GNU Bison 3.8.2. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, + Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, + especially those whose name start with YY_ or yy_. They are + private implementation details that can be changed or removed. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output, and Bison version. */ +#define YYBISON 30802 + +/* Bison version string. */ +#define YYBISON_VERSION "3.8.2" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 2 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* "%code top" blocks. */ +#line 7 "kalmia.y" + + #include <stdio.h> + #include <stdlib.h> + #include <stdarg.h> + #include <string.h> + +#line 75 "kalmia.tab.c" +/* Substitute the type names. */ +#define YYSTYPE KALMIASTYPE +#define YYLTYPE KALMIALTYPE +/* Substitute the variable and function names. */ +#define yyparse kalmiaparse +#define yylex kalmialex +#define yyerror kalmiaerror +#define yydebug kalmiadebug +#define yynerrs kalmianerrs + + +# ifndef YY_CAST +# ifdef __cplusplus +# define YY_CAST(Type, Val) static_cast<Type> (Val) +# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val) +# else +# define YY_CAST(Type, Val) ((Type) (Val)) +# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) +# endif +# endif +# ifndef YY_NULLPTR +# if defined __cplusplus +# if 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# else +# define YY_NULLPTR ((void*)0) +# endif +# endif + +#include "kalmia.tab.h" +/* Symbol kind. */ +enum yysymbol_kind_t +{ + YYSYMBOL_YYEMPTY = -2, + YYSYMBOL_YYEOF = 0, /* "end of file" */ + YYSYMBOL_YYerror = 1, /* error */ + YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ + YYSYMBOL_PROLOG = 3, /* PROLOG */ + YYSYMBOL_S_TAG_OPEN = 4, /* S_TAG_OPEN */ + YYSYMBOL_E_TAG_OPEN = 5, /* E_TAG_OPEN */ + YYSYMBOL_TAG_CLOSE = 6, /* TAG_CLOSE */ + YYSYMBOL_EMPTY_TAG_CLOSE = 7, /* EMPTY_TAG_CLOSE */ + YYSYMBOL_NAME = 8, /* NAME */ + YYSYMBOL_ATTR = 9, /* ATTR */ + YYSYMBOL_TEXT = 10, /* TEXT */ + YYSYMBOL_CONTENT = 11, /* CONTENT */ + YYSYMBOL_12_ = 12, /* '=' */ + YYSYMBOL_13_ = 13, /* '"' */ + YYSYMBOL_YYACCEPT = 14, /* $accept */ + YYSYMBOL_document = 15, /* document */ + YYSYMBOL_tags = 16, /* tags */ + YYSYMBOL_tag = 17, /* tag */ + YYSYMBOL_start_tag = 18, /* start_tag */ + YYSYMBOL_empty_tag = 19, /* empty_tag */ + YYSYMBOL_end_tag = 20, /* end_tag */ + YYSYMBOL_attributes = 21, /* attributes */ + YYSYMBOL_attribute = 22 /* attribute */ +}; +typedef enum yysymbol_kind_t yysymbol_kind_t; + + + +/* Unqualified %code blocks. */ +#line 36 "kalmia.y" + + /* flex definitions */ + int yylex(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t scanner); + int kalmialex_init(yyscan_t *); + void kalmiaset_in(FILE *, yyscan_t); + int kalmialex_destroy(yyscan_t); + + int yyerror(YYLTYPE *yyllocp, yyscan_t unused, + struct kai_tag_t **unused2, const char *msg); + + #define TAG_MISMATCH(a, b) \ + do { \ + char buf[1024]; \ + snprintf(buf, 1024, "Tag name mismatch: \"%s\" != \"%s\"", a, b); \ + yyerror(&yylloc, NULL, NULL, (const char*) buf); \ + YYABORT; \ + } while (0) + + /* create/destroy kai_attr_t */ + struct kai_attr_t * kai_attr_new(char *key, char *value); + struct kai_attr_t * kai_attr_last(struct kai_attr_t *head); + void kai_attr_destroy(struct kai_attr_t *attr); + + /* create/destroy kai_tag_t */ + struct kai_tag_t * kai_tag_new(char *type, struct kai_attr_t *attrs); + struct kai_tag_t * kai_tag_last(struct kai_tag_t *head); + void kai_tag_destroy(struct kai_tag_t *tag); + +#line 171 "kalmia.tab.c" + +#ifdef short +# undef short +#endif + +/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure + <limits.h> and (if available) <stdint.h> are included + so that the code can choose integer types of a good width. */ + +#ifndef __PTRDIFF_MAX__ +# include <limits.h> /* INFRINGES ON USER NAME SPACE */ +# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ +# include <stdint.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_STDINT_H +# endif +#endif + +/* Narrow types that promote to a signed type and that can represent a + signed or unsigned integer of at least N bits. In tables they can + save space and decrease cache pressure. Promoting to a signed type + helps avoid bugs in integer arithmetic. */ + +#ifdef __INT_LEAST8_MAX__ +typedef __INT_LEAST8_TYPE__ yytype_int8; +#elif defined YY_STDINT_H +typedef int_least8_t yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef __INT_LEAST16_MAX__ +typedef __INT_LEAST16_TYPE__ yytype_int16; +#elif defined YY_STDINT_H +typedef int_least16_t yytype_int16; +#else +typedef short yytype_int16; +#endif + +/* Work around bug in HP-UX 11.23, which defines these macros + incorrectly for preprocessor constants. This workaround can likely + be removed in 2023, as HPE has promised support for HP-UX 11.23 + (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of + <https://h20195.www2.hpe.com/V2/getpdf.aspx/4AA4-7673ENW.pdf>. */ +#ifdef __hpux +# undef UINT_LEAST8_MAX +# undef UINT_LEAST16_MAX +# define UINT_LEAST8_MAX 255 +# define UINT_LEAST16_MAX 65535 +#endif + +#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ +typedef __UINT_LEAST8_TYPE__ yytype_uint8; +#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ + && UINT_LEAST8_MAX <= INT_MAX) +typedef uint_least8_t yytype_uint8; +#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX +typedef unsigned char yytype_uint8; +#else +typedef short yytype_uint8; +#endif + +#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ +typedef __UINT_LEAST16_TYPE__ yytype_uint16; +#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ + && UINT_LEAST16_MAX <= INT_MAX) +typedef uint_least16_t yytype_uint16; +#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX +typedef unsigned short yytype_uint16; +#else +typedef int yytype_uint16; +#endif + +#ifndef YYPTRDIFF_T +# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ +# define YYPTRDIFF_T __PTRDIFF_TYPE__ +# define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ +# elif defined PTRDIFF_MAX +# ifndef ptrdiff_t +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# endif +# define YYPTRDIFF_T ptrdiff_t +# define YYPTRDIFF_MAXIMUM PTRDIFF_MAX +# else +# define YYPTRDIFF_T long +# define YYPTRDIFF_MAXIMUM LONG_MAX +# endif +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned +# endif +#endif + +#define YYSIZE_MAXIMUM \ + YY_CAST (YYPTRDIFF_T, \ + (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ + ? YYPTRDIFF_MAXIMUM \ + : YY_CAST (YYSIZE_T, -1))) + +#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) + + +/* Stored state numbers (used for stacks). */ +typedef yytype_int8 yy_state_t; + +/* State numbers in computations. */ +typedef int yy_state_fast_t; + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + + +#ifndef YY_ATTRIBUTE_PURE +# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) +# else +# define YY_ATTRIBUTE_PURE +# endif +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +# else +# define YY_ATTRIBUTE_UNUSED +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YY_USE(E) ((void) (E)) +#else +# define YY_USE(E) /* empty */ +#endif + +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +#if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ +# if __GNUC__ * 100 + __GNUC_MINOR__ < 407 +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") +# else +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# endif +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + +#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ +# define YY_IGNORE_USELESS_CAST_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") +# define YY_IGNORE_USELESS_CAST_END \ + _Pragma ("GCC diagnostic pop") +#endif +#ifndef YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_END +#endif + + +#define YY_ASSERT(E) ((void) (0 && (E))) + +#if 1 + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* 1 */ + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined KALMIALTYPE_IS_TRIVIAL && KALMIALTYPE_IS_TRIVIAL \ + && defined KALMIASTYPE_IS_TRIVIAL && KALMIASTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yy_state_t yyss_alloc; + YYSTYPE yyvs_alloc; + YYLTYPE yyls_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE) \ + + YYSIZEOF (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYPTRDIFF_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / YYSIZEOF (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYPTRDIFF_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 7 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 31 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 14 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 9 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 16 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 31 + +/* YYMAXUTOK -- Last valid token kind. */ +#define YYMAXUTOK 266 + + +/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, with out-of-bounds checking. */ +#define YYTRANSLATE(YYX) \ + (0 <= (YYX) && (YYX) <= YYMAXUTOK \ + ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ + : YYSYMBOL_YYUNDEF) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex. */ +static const yytype_int8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 13, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 12, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11 +}; + +#if KALMIADEBUG +/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_uint8 yyrline[] = +{ + 0, 94, 94, 98, 99, 104, 110, 117, 124, 128, + 133, 142, 147, 156, 161, 162, 166 +}; +#endif + +/** Accessing symbol of state STATE. */ +#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) + +#if 1 +/* The user-facing name of the symbol whose (internal) number is + YYSYMBOL. No bounds checking. */ +static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; + +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "\"end of file\"", "error", "\"invalid token\"", "PROLOG", "S_TAG_OPEN", + "E_TAG_OPEN", "TAG_CLOSE", "EMPTY_TAG_CLOSE", "NAME", "ATTR", "TEXT", + "CONTENT", "'='", "'\"'", "$accept", "document", "tags", "tag", + "start_tag", "empty_tag", "end_tag", "attributes", "attribute", YY_NULLPTR +}; + +static const char * +yysymbol_name (yysymbol_kind_t yysymbol) +{ + return yytname[yysymbol]; +} +#endif + +#define YYPACT_NINF (-6) + +#define yypact_value_is_default(Yyn) \ + ((Yyn) == YYPACT_NINF) + +#define YYTABLE_NINF (-1) + +#define yytable_value_is_error(Yyn) \ + 0 + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int8 yypact[] = +{ + 8, 11, 17, 10, -6, -4, -6, -6, 3, 12, + 14, -1, -6, -6, -6, -6, 9, 7, -6, 16, + -6, -6, -6, 13, -6, -6, -6, -6, 15, 18, + -6 +}; + +/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_int8 yydefact[] = +{ + 0, 0, 0, 0, 2, 0, 8, 1, 0, 0, + 0, 0, 3, 5, 9, 11, 0, 0, 14, 0, + 6, 4, 7, 0, 10, 12, 15, 13, 0, 0, + 16 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -6, -6, -6, -3, -6, -6, -5, -6, 6 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + 0, 2, 11, 4, 5, 6, 13, 17, 18 +}; + +/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_int8 yytable[] = +{ + 3, 9, 12, 3, 9, 20, 22, 10, 21, 14, + 15, 1, 16, 24, 25, 3, 16, 7, 8, 9, + 19, 23, 27, 26, 0, 29, 28, 0, 0, 0, + 0, 30 +}; + +static const yytype_int8 yycheck[] = +{ + 4, 5, 5, 4, 5, 10, 11, 11, 11, 6, + 7, 3, 9, 6, 7, 4, 9, 0, 8, 5, + 8, 12, 6, 17, -1, 10, 13, -1, -1, -1, + -1, 13 +}; + +/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of + state STATE-NUM. */ +static const yytype_int8 yystos[] = +{ + 0, 3, 15, 4, 17, 18, 19, 0, 8, 5, + 11, 16, 17, 20, 6, 7, 9, 21, 22, 8, + 20, 17, 20, 12, 6, 7, 22, 6, 13, 10, + 13 +}; + +/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ +static const yytype_int8 yyr1[] = +{ + 0, 14, 15, 16, 16, 17, 17, 17, 17, 18, + 18, 19, 19, 20, 21, 21, 22 +}; + +/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ +static const yytype_int8 yyr2[] = +{ + 0, 2, 2, 1, 2, 2, 3, 3, 1, 3, + 4, 3, 4, 3, 1, 2, 5 +}; + + +enum { YYENOMEM = -2 }; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = KALMIAEMPTY) + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab +#define YYNOMEM goto yyexhaustedlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ + do \ + if (yychar == KALMIAEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (&yylloc, scanner, document, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ + while (0) + +/* Backward compatibility with an undocumented macro. + Use KALMIAerror or KALMIAUNDEF. */ +#define YYERRCODE KALMIAUNDEF + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (N) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (0) +#endif + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) + + +/* Enable debugging if requested. */ +#if KALMIADEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + + +/* YYLOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +# ifndef YYLOCATION_PRINT + +# if defined YY_LOCATION_PRINT + + /* Temporary convenience wrapper in case some people defined the + undocumented and private YY_LOCATION_PRINT macros. */ +# define YYLOCATION_PRINT(File, Loc) YY_LOCATION_PRINT(File, *(Loc)) + +# elif defined KALMIALTYPE_IS_TRIVIAL && KALMIALTYPE_IS_TRIVIAL + +/* Print *YYLOCP on YYO. Private, do not rely on its existence. */ + +YY_ATTRIBUTE_UNUSED +static int +yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp) +{ + int res = 0; + int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0; + if (0 <= yylocp->first_line) + { + res += YYFPRINTF (yyo, "%d", yylocp->first_line); + if (0 <= yylocp->first_column) + res += YYFPRINTF (yyo, ".%d", yylocp->first_column); + } + if (0 <= yylocp->last_line) + { + if (yylocp->first_line < yylocp->last_line) + { + res += YYFPRINTF (yyo, "-%d", yylocp->last_line); + if (0 <= end_col) + res += YYFPRINTF (yyo, ".%d", end_col); + } + else if (0 <= end_col && yylocp->first_column < end_col) + res += YYFPRINTF (yyo, "-%d", end_col); + } + return res; +} + +# define YYLOCATION_PRINT yy_location_print_ + + /* Temporary convenience wrapper in case some people defined the + undocumented and private YY_LOCATION_PRINT macros. */ +# define YY_LOCATION_PRINT(File, Loc) YYLOCATION_PRINT(File, &(Loc)) + +# else + +# define YYLOCATION_PRINT(File, Loc) ((void) 0) + /* Temporary convenience wrapper in case some people defined the + undocumented and private YY_LOCATION_PRINT macros. */ +# define YY_LOCATION_PRINT YYLOCATION_PRINT + +# endif +# endif /* !defined YYLOCATION_PRINT */ + + +# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Kind, Value, Location, scanner, document); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*-----------------------------------. +| Print this symbol's value on YYO. | +`-----------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyo, + yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, yyscan_t scanner, struct kai_tag_t **document) +{ + FILE *yyoutput = yyo; + YY_USE (yyoutput); + YY_USE (yylocationp); + YY_USE (scanner); + YY_USE (document); + if (!yyvaluep) + return; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YY_USE (yykind); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + +/*---------------------------. +| Print this symbol on YYO. | +`---------------------------*/ + +static void +yy_symbol_print (FILE *yyo, + yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, yyscan_t scanner, struct kai_tag_t **document) +{ + YYFPRINTF (yyo, "%s %s (", + yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); + + YYLOCATION_PRINT (yyo, yylocationp); + YYFPRINTF (yyo, ": "); + yy_symbol_value_print (yyo, yykind, yyvaluep, yylocationp, scanner, document); + YYFPRINTF (yyo, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, + int yyrule, yyscan_t scanner, struct kai_tag_t **document) +{ + int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), + &yyvsp[(yyi + 1) - (yynrhs)], + &(yylsp[(yyi + 1) - (yynrhs)]), scanner, document); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, yylsp, Rule, scanner, document); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !KALMIADEBUG */ +# define YYDPRINTF(Args) ((void) 0) +# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !KALMIADEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +/* Context of a parse error. */ +typedef struct +{ + yy_state_t *yyssp; + yysymbol_kind_t yytoken; + YYLTYPE *yylloc; +} yypcontext_t; + +/* Put in YYARG at most YYARGN of the expected tokens given the + current YYCTX, and return the number of tokens stored in YYARG. If + YYARG is null, return the number of expected tokens (guaranteed to + be less than YYNTOKENS). Return YYENOMEM on memory exhaustion. + Return 0 if there are more than YYARGN expected tokens, yet fill + YYARG up to YYARGN. */ +static int +yypcontext_expected_tokens (const yypcontext_t *yyctx, + yysymbol_kind_t yyarg[], int yyargn) +{ + /* Actual size of YYARG. */ + int yycount = 0; + int yyn = yypact[+*yyctx->yyssp]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (!yyarg) + ++yycount; + else if (yycount == yyargn) + return 0; + else + yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx); + } + } + if (yyarg && yycount == 0 && 0 < yyargn) + yyarg[0] = YYSYMBOL_YYEMPTY; + return yycount; +} + + + + +#ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S))) +# else +/* Return the length of YYSTR. */ +static YYPTRDIFF_T +yystrlen (const char *yystr) +{ + YYPTRDIFF_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +#endif + +#ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +#endif + +#ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYPTRDIFF_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYPTRDIFF_T yyn = 0; + char const *yyp = yystr; + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + else + goto append; + + append: + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (yyres) + return yystpcpy (yyres, yystr) - yyres; + else + return yystrlen (yystr); +} +#endif + + +static int +yy_syntax_error_arguments (const yypcontext_t *yyctx, + yysymbol_kind_t yyarg[], int yyargn) +{ + /* Actual size of YYARG. */ + int yycount = 0; + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yyctx->yytoken != YYSYMBOL_YYEMPTY) + { + int yyn; + if (yyarg) + yyarg[yycount] = yyctx->yytoken; + ++yycount; + yyn = yypcontext_expected_tokens (yyctx, + yyarg ? yyarg + 1 : yyarg, yyargn - 1); + if (yyn == YYENOMEM) + return YYENOMEM; + else + yycount += yyn; + } + return yycount; +} + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return -1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return YYENOMEM if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg, + const yypcontext_t *yyctx) +{ + enum { YYARGS_MAX = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat: reported tokens (one for the "unexpected", + one per "expected"). */ + yysymbol_kind_t yyarg[YYARGS_MAX]; + /* Cumulated lengths of YYARG. */ + YYPTRDIFF_T yysize = 0; + + /* Actual size of YYARG. */ + int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX); + if (yycount == YYENOMEM) + return YYENOMEM; + + switch (yycount) + { +#define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + default: /* Avoid compiler warnings. */ + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +#undef YYCASE_ + } + + /* Compute error message size. Don't count the "%s"s, but reserve + room for the terminator. */ + yysize = yystrlen (yyformat) - 2 * yycount + 1; + { + int yyi; + for (yyi = 0; yyi < yycount; ++yyi) + { + YYPTRDIFF_T yysize1 + = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]); + if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM) + yysize = yysize1; + else + return YYENOMEM; + } + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return -1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]); + yyformat += 2; + } + else + { + ++yyp; + ++yyformat; + } + } + return 0; +} + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, + yysymbol_kind_t yykind, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, yyscan_t scanner, struct kai_tag_t **document) +{ + YY_USE (yyvaluep); + YY_USE (yylocationp); + YY_USE (scanner); + YY_USE (document); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YY_USE (yykind); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (yyscan_t scanner, struct kai_tag_t **document) +{ +/* Lookahead token kind. */ +int yychar; + + +/* The semantic value of the lookahead symbol. */ +/* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ +YY_INITIAL_VALUE (static YYSTYPE yyval_default;) +YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); + +/* Location data for the lookahead symbol. */ +static YYLTYPE yyloc_default +# if defined KALMIALTYPE_IS_TRIVIAL && KALMIALTYPE_IS_TRIVIAL + = { 1, 1, 1, 1 } +# endif +; +YYLTYPE yylloc = yyloc_default; + + /* Number of syntax errors so far. */ + int yynerrs = 0; + + yy_state_fast_t yystate = 0; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus = 0; + + /* Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* Their size. */ + YYPTRDIFF_T yystacksize = YYINITDEPTH; + + /* The state stack: array, bottom, top. */ + yy_state_t yyssa[YYINITDEPTH]; + yy_state_t *yyss = yyssa; + yy_state_t *yyssp = yyss; + + /* The semantic value stack: array, bottom, top. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp = yyvs; + + /* The location stack: array, bottom, top. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp = yyls; + + int yyn; + /* The return value of yyparse. */ + int yyresult; + /* Lookahead symbol kind. */ + yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + YYLTYPE yyloc; + + /* The locations where the error started and ended. */ + YYLTYPE yyerror_range[3]; + + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf; + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yychar = KALMIAEMPTY; /* Cause a token to be read. */ + + yylsp[0] = yylloc; + goto yysetstate; + + +/*------------------------------------------------------------. +| yynewstate -- push a new state, which is found in yystate. | +`------------------------------------------------------------*/ +yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + +/*--------------------------------------------------------------------. +| yysetstate -- set current state (the top of the stack) to yystate. | +`--------------------------------------------------------------------*/ +yysetstate: + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + YY_ASSERT (0 <= yystate && yystate < YYNSTATES); + YY_IGNORE_USELESS_CAST_BEGIN + *yyssp = YY_CAST (yy_state_t, yystate); + YY_IGNORE_USELESS_CAST_END + YY_STACK_PRINT (yyss, yyssp); + + if (yyss + yystacksize - 1 <= yyssp) +#if !defined yyoverflow && !defined YYSTACK_RELOCATE + YYNOMEM; +#else + { + /* Get the current used size of the three stacks, in elements. */ + YYPTRDIFF_T yysize = yyssp - yyss + 1; + +# if defined yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + yy_state_t *yyss1 = yyss; + YYSTYPE *yyvs1 = yyvs; + YYLTYPE *yyls1 = yyls; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * YYSIZEOF (*yyssp), + &yyvs1, yysize * YYSIZEOF (*yyvsp), + &yyls1, yysize * YYSIZEOF (*yylsp), + &yystacksize); + yyss = yyss1; + yyvs = yyvs1; + yyls = yyls1; + } +# else /* defined YYSTACK_RELOCATE */ + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + YYNOMEM; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yy_state_t *yyss1 = yyss; + union yyalloc *yyptr = + YY_CAST (union yyalloc *, + YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); + if (! yyptr) + YYNOMEM; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); + YYSTACK_RELOCATE (yyls_alloc, yyls); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + yylsp = yyls + yysize - 1; + + YY_IGNORE_USELESS_CAST_BEGIN + YYDPRINTF ((stderr, "Stack size increased to %ld\n", + YY_CAST (long, yystacksize))); + YY_IGNORE_USELESS_CAST_END + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } +#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ + + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ + if (yychar == KALMIAEMPTY) + { + YYDPRINTF ((stderr, "Reading a token\n")); + yychar = yylex (&yylval, &yylloc, scanner); + } + + if (yychar <= KALMIAEOF) + { + yychar = KALMIAEOF; + yytoken = YYSYMBOL_YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else if (yychar == KALMIAerror) + { + /* The scanner already issued an error message, process directly + to error recovery. But do not keep the error token as + lookahead, it is too special and may lead us to an endless + loop in error recovery. */ + yychar = KALMIAUNDEF; + yytoken = YYSYMBOL_YYerror; + yyerror_range[1] = yylloc; + goto yyerrlab1; + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + *++yylsp = yylloc; + + /* Discard the shifted token. */ + yychar = KALMIAEMPTY; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + /* Default location. */ + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); + yyerror_range[1] = yyloc; + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: /* document: PROLOG tag */ +#line 94 "kalmia.y" + { *document = (yyvsp[0].tag); } +#line 1531 "kalmia.tab.c" + break; + + case 3: /* tags: tag */ +#line 98 "kalmia.y" + { (yyval.tag) = (yyvsp[0].tag); } +#line 1537 "kalmia.tab.c" + break; + + case 4: /* tags: tags tag */ +#line 99 "kalmia.y" + { (yyval.tag) = (yyvsp[-1].tag); kai_tag_last((yyval.tag))->next = (yyvsp[0].tag); } +#line 1543 "kalmia.tab.c" + break; + + case 5: /* tag: start_tag end_tag */ +#line 105 "kalmia.y" + { + (yyval.tag) = (yyvsp[-1].tag); + if (strcmp((yyval.tag)->type, (yyvsp[0].string)) != 0) TAG_MISMATCH((yyval.tag)->type, (yyvsp[0].string)); + free((yyvsp[0].string)); + } +#line 1553 "kalmia.tab.c" + break; + + case 6: /* tag: start_tag CONTENT end_tag */ +#line 111 "kalmia.y" + { + (yyval.tag) = (yyvsp[-2].tag); + (yyval.tag)->content = (yyvsp[-1].string); + if (strcmp((yyval.tag)->type, (yyvsp[0].string)) != 0) TAG_MISMATCH((yyval.tag)->type, (yyvsp[0].string)); + free((yyvsp[0].string)); + } +#line 1564 "kalmia.tab.c" + break; + + case 7: /* tag: start_tag tags end_tag */ +#line 118 "kalmia.y" + { + (yyval.tag) = (yyvsp[-2].tag); + (yyval.tag)->children = (yyvsp[-1].tag); + if (strcmp((yyval.tag)->type, (yyvsp[0].string)) != 0) TAG_MISMATCH((yyval.tag)->type, (yyvsp[0].string)); + free((yyvsp[0].string)); + } +#line 1575 "kalmia.tab.c" + break; + + case 8: /* tag: empty_tag */ +#line 124 "kalmia.y" + { (yyval.tag) = (yyvsp[0].tag); } +#line 1581 "kalmia.tab.c" + break; + + case 9: /* start_tag: S_TAG_OPEN NAME TAG_CLOSE */ +#line 129 "kalmia.y" + { + (yyval.tag) = kai_tag_new((yyvsp[-1].string), NULL); + if ((yyval.tag) == NULL) YYNOMEM; + } +#line 1590 "kalmia.tab.c" + break; + + case 10: /* start_tag: S_TAG_OPEN NAME attributes TAG_CLOSE */ +#line 134 "kalmia.y" + { + (yyval.tag) = kai_tag_new((yyvsp[-2].string), (yyvsp[-1].attr)); + if ((yyval.tag) == NULL) YYNOMEM; + } +#line 1599 "kalmia.tab.c" + break; + + case 11: /* empty_tag: S_TAG_OPEN NAME EMPTY_TAG_CLOSE */ +#line 143 "kalmia.y" + { + (yyval.tag) = kai_tag_new((yyvsp[-1].string), NULL); + if ((yyval.tag) == NULL) YYNOMEM; + } +#line 1608 "kalmia.tab.c" + break; + + case 12: /* empty_tag: S_TAG_OPEN NAME attributes EMPTY_TAG_CLOSE */ +#line 148 "kalmia.y" + { + (yyval.tag) = kai_tag_new((yyvsp[-2].string), (yyvsp[-1].attr)); + if ((yyval.tag) == NULL) YYNOMEM; + } +#line 1617 "kalmia.tab.c" + break; + + case 13: /* end_tag: E_TAG_OPEN NAME TAG_CLOSE */ +#line 156 "kalmia.y" + { (yyval.string) = (yyvsp[-1].string); } +#line 1623 "kalmia.tab.c" + break; + + case 14: /* attributes: attribute */ +#line 161 "kalmia.y" + { (yyval.attr) = (yyvsp[0].attr); } +#line 1629 "kalmia.tab.c" + break; + + case 15: /* attributes: attributes attribute */ +#line 162 "kalmia.y" + { (yyval.attr) = (yyvsp[-1].attr); kai_attr_last((yyval.attr))->next = (yyvsp[0].attr); } +#line 1635 "kalmia.tab.c" + break; + + case 16: /* attribute: ATTR '=' '"' TEXT '"' */ +#line 167 "kalmia.y" + { + (yyval.attr) = kai_attr_new((yyvsp[-4].string), (yyvsp[-1].string)); + if ((yyval.attr) == NULL) YYNOMEM; + } +#line 1644 "kalmia.tab.c" + break; + + +#line 1648 "kalmia.tab.c" + + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + + *++yyvsp = yyval; + *++yylsp = yyloc; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + { + const int yylhs = yyr1[yyn] - YYNTOKENS; + const int yyi = yypgoto[yylhs] + *yyssp; + yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp + ? yytable[yyi] + : yydefgoto[yylhs]); + } + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == KALMIAEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; + { + yypcontext_t yyctx + = {yyssp, yytoken, &yylloc}; + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx); + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == -1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = YY_CAST (char *, + YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc))); + if (yymsg) + { + yysyntax_error_status + = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx); + yymsgp = yymsg; + } + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = YYENOMEM; + } + } + yyerror (&yylloc, scanner, document, yymsgp); + if (yysyntax_error_status == YYENOMEM) + YYNOMEM; + } + } + + yyerror_range[1] = yylloc; + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= KALMIAEOF) + { + /* Return failure if at end of input. */ + if (yychar == KALMIAEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, &yylloc, scanner, document); + yychar = KALMIAEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + /* Pacify compilers when the user code never invokes YYERROR and the + label yyerrorlab therefore never appears in user code. */ + if (0) + YYERROR; + ++yynerrs; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + /* Pop stack until we find a state that shifts the error token. */ + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYSYMBOL_YYerror; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + yyerror_range[1] = *yylsp; + yydestruct ("Error: popping", + YY_ACCESSING_SYMBOL (yystate), yyvsp, yylsp, scanner, document); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + yyerror_range[2] = yylloc; + ++yylsp; + YYLLOC_DEFAULT (*yylsp, yyerror_range, 2); + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturnlab; + + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturnlab; + + +/*-----------------------------------------------------------. +| yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | +`-----------------------------------------------------------*/ +yyexhaustedlab: + yyerror (&yylloc, scanner, document, YY_("memory exhausted")); + yyresult = 2; + goto yyreturnlab; + + +/*----------------------------------------------------------. +| yyreturnlab -- parsing is finished, clean up and return. | +`----------------------------------------------------------*/ +yyreturnlab: + if (yychar != KALMIAEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, &yylloc, scanner, document); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, yylsp, scanner, document); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + return yyresult; +} + +#line 174 "kalmia.y" + + + +/* print an error message */ +int yyerror( + YYLTYPE *yyllocp, + yyscan_t unused, + struct kai_tag_t **unused2, + const char *msg) +{ + fprintf( + stderr, "[%d:%d]: %s\n", + yyllocp->first_line, yyllocp->first_column, msg + ); + return 1; +} + + + +/* create a new kai_attr_t object */ +struct kai_attr_t * kai_attr_new(char *key, char *value) +{ + struct kai_attr_t *attr = malloc(sizeof(struct kai_attr_t)); + if (attr == NULL) { + return NULL; + } + attr->key = key; + attr->value = value; + attr->next = NULL; + return attr; +} + +/* get the end of a kai_attr_t list */ +struct kai_attr_t * kai_attr_last(struct kai_attr_t *head) +{ + struct kai_attr_t *ptr = head; + while (ptr->next != NULL) { + ptr = ptr->next; + } + return ptr; +} + +/* destroy a kai_attr_t list */ +void kai_attr_destroy(struct kai_attr_t *attr) +{ + if (attr == NULL) { + return; + } + + kai_attr_destroy(attr->next); + free(attr->key); + free(attr->value); + free(attr); +} + + + +/* create a kai_tag_t object */ +struct kai_tag_t * kai_tag_new(char *type, struct kai_attr_t *attrs) +{ + struct kai_tag_t *tag = malloc(sizeof(struct kai_tag_t)); + if (tag == NULL) { + return NULL; + } + + tag->type = type; + tag->attrs = attrs; + tag->children = NULL; + tag->content = NULL; + tag->next = NULL; + return tag; +} + +/* get the end of a kai_tag_t list */ +struct kai_tag_t * kai_tag_last(struct kai_tag_t *head) +{ + struct kai_tag_t *ptr = head; + while (ptr->next != NULL) { + ptr = ptr->next; + } + return ptr; +} + +/* destroy a kai_tag_t list */ +void kai_tag_destroy(struct kai_tag_t *tag) +{ + if (tag == NULL) { + return; + } + + free(tag->type); + kai_attr_destroy(tag->attrs); + kai_tag_destroy(tag->children); + free(tag->content); + kai_tag_destroy(tag->next); + free(tag); +} + + + +/* parse a file into a document */ +struct kai_tag_t * kai_parse_file(const char *filename) +{ + FILE *file = fopen(filename, "r"); + if (file == NULL) { + fprintf(stderr, "Could not open file \"%s\"\n", filename); + return NULL; + } + + yyscan_t scanner; + struct kai_tag_t *document; + + kalmialex_init(&scanner); + kalmiaset_in(file, scanner); + int result = kalmiaparse(scanner, &document); + kalmialex_destroy(scanner); + fclose(file); + + if (result != 0) { + /* parse function will print error message */ + return NULL; + } + + return document; +} diff --git a/src/xml/kalmia.tab.h b/src/xml/kalmia.tab.h new file mode 100644 index 0000000..987ac6c --- /dev/null +++ b/src/xml/kalmia.tab.h @@ -0,0 +1,141 @@ +/* A Bison parser, made by GNU Bison 3.8.2. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, + Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, + especially those whose name start with YY_ or yy_. They are + private implementation details that can be changed or removed. */ + +#ifndef YY_KALMIA_KALMIA_TAB_H_INCLUDED +# define YY_KALMIA_KALMIA_TAB_H_INCLUDED +/* Debug traces. */ +#ifndef KALMIADEBUG +# if defined YYDEBUG +#if YYDEBUG +# define KALMIADEBUG 1 +# else +# define KALMIADEBUG 0 +# endif +# else /* ! defined YYDEBUG */ +# define KALMIADEBUG 0 +# endif /* ! defined YYDEBUG */ +#endif /* ! defined KALMIADEBUG */ +#if KALMIADEBUG +extern int kalmiadebug; +#endif +/* "%code requires" blocks. */ +#line 13 "kalmia.y" + + typedef void* yyscan_t; + + struct kai_attr_t { + char *key; + char *value; + struct kai_attr_t *next; + }; + + struct kai_tag_t { + char *type; + struct kai_attr_t *attrs; + + struct kai_tag_t *children; + char *content; + + struct kai_tag_t *next; + }; + + struct kai_tag_t * kai_parse_file(const char *filename); + void kai_tag_destroy(struct kai_tag_t *tag); + +#line 80 "kalmia.tab.h" + +/* Token kinds. */ +#ifndef KALMIATOKENTYPE +# define KALMIATOKENTYPE + enum kalmiatokentype + { + KALMIAEMPTY = -2, + KALMIAEOF = 0, /* "end of file" */ + KALMIAerror = 256, /* error */ + KALMIAUNDEF = 257, /* "invalid token" */ + PROLOG = 258, /* PROLOG */ + S_TAG_OPEN = 259, /* S_TAG_OPEN */ + E_TAG_OPEN = 260, /* E_TAG_OPEN */ + TAG_CLOSE = 261, /* TAG_CLOSE */ + EMPTY_TAG_CLOSE = 262, /* EMPTY_TAG_CLOSE */ + NAME = 263, /* NAME */ + ATTR = 264, /* ATTR */ + TEXT = 265, /* TEXT */ + CONTENT = 266 /* CONTENT */ + }; + typedef enum kalmiatokentype kalmiatoken_kind_t; +#endif + +/* Value type. */ +#if ! defined KALMIASTYPE && ! defined KALMIASTYPE_IS_DECLARED +union KALMIASTYPE +{ +#line 65 "kalmia.y" + + char *string; + struct kai_attr_t *attr; + struct kai_tag_t *tag; + +#line 114 "kalmia.tab.h" + +}; +typedef union KALMIASTYPE KALMIASTYPE; +# define KALMIASTYPE_IS_TRIVIAL 1 +# define KALMIASTYPE_IS_DECLARED 1 +#endif + +/* Location type. */ +#if ! defined KALMIALTYPE && ! defined KALMIALTYPE_IS_DECLARED +typedef struct KALMIALTYPE KALMIALTYPE; +struct KALMIALTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +}; +# define KALMIALTYPE_IS_DECLARED 1 +# define KALMIALTYPE_IS_TRIVIAL 1 +#endif + + + + +int kalmiaparse (yyscan_t scanner, struct kai_tag_t **document); + + +#endif /* !YY_KALMIA_KALMIA_TAB_H_INCLUDED */ diff --git a/src/xml/xml.c b/src/xml/xml.c new file mode 100644 index 0000000..e2aa008 --- /dev/null +++ b/src/xml/xml.c @@ -0,0 +1,20 @@ +#include "xml.h" + +/* parse a string into a document */ +struct kai_tag_t * kai_parse_string(const char *str) +{ + yyscan_t scanner; + struct kai_tag_t *document; + + kalmialex_init(&scanner); + YY_BUFFER_STATE buf = kalmia_scan_string(str, scanner); + int result = kalmiaparse(scanner, &document); + kalmia_delete_buffer(buf, scanner); + kalmialex_destroy(scanner); + + if (result != 0) { + return NULL; + } + + return document; +} diff --git a/src/xml/xml.h b/src/xml/xml.h new file mode 100644 index 0000000..238177e --- /dev/null +++ b/src/xml/xml.h @@ -0,0 +1,11 @@ +#ifndef KALMIA_XML_H +#define KALMIA_XML_H + +#define YYLTYPE KALMIALTYPE +#define YYSTYPE KALMIASTYPE +#include "xml/kalmia.tab.h" +#include "xml/kalmia.lex.h" + +struct kai_tag_t * kai_parse_string(const char *str); + +#endif diff --git a/yy/makefile b/yy/makefile index a2022a2..6567b56 100644 --- a/yy/makefile +++ b/yy/makefile @@ -1,6 +1,6 @@ WARNINGS = -Wall -Wextra -Wpedantic -all: kalmia +all: kalmia.tab.c kalmia.lex.c kalmia.tab.c: kalmia.y bison -o "$@" --header=kalmia.tab.h kalmia.y @@ -8,8 +8,8 @@ kalmia.tab.c: kalmia.y kalmia.lex.c: kalmia.l flex -o "$@" --header-file="kalmia.lex.h" kalmia.l -kalmia: kalmia.tab.c kalmia.lex.c main.c - gcc -g -o kalmia ${WARNINGS} main.c kalmia.tab.c kalmia.lex.c +demo: kalmia.tab.c kalmia.lex.c demo.c + gcc -g -o demo ${WARNINGS} demo.c kalmia.tab.c kalmia.lex.c clean: - rm kalmia.lex.c kalmia.lex.h kalmia.tab.c kalmia.tab.h kalmia + rm kalmia.lex.c kalmia.lex.h kalmia.tab.c kalmia.tab.h demo |