16 enum { TOK_SYM, TOK_ID, TOK_NUM, TOK_STR };
18 static struct ts_node *read_node(struct parser *pstate);
19 static int read_array(struct parser *pstate, struct ts_value *tsv, char endsym);
20 static int next_token(struct parser *pstate);
22 static int print_attr(struct ts_attr *attr, struct ts_io *io, int level);
23 static char *value_to_str(struct ts_value *value);
24 static int tree_level(struct ts_node *n);
25 static const char *indent(int x);
26 static const char *toktypestr(int type);
28 #define EXPECT(type) \
30 if(next_token(pst) != (type)) { \
31 fprintf(stderr, "expected %s token\n", toktypestr(type)); \
36 #define EXPECT_SYM(c) \
38 if(next_token(pst) != TOK_SYM || pst->token[0] != (c)) { \
39 fprintf(stderr, "expected symbol: %c\n", c); \
45 struct ts_node *ts_text_load(struct ts_io *io)
48 struct parser pstate, *pst = &pstate;
49 struct ts_node *node = 0;
54 if(!(pstate.token = ts_dynarr_alloc(0, 1))) {
55 perror("failed to allocate token string");
60 if(!(root_name = strdup(pst->token))) {
61 perror("failed to allocate root node name");
62 ts_dynarr_free(pst->token);
66 if(!(node = read_node(pst))) {
67 ts_dynarr_free(pst->token);
70 node->name = root_name;
73 ts_dynarr_free(pst->token);
77 static int read_value(struct parser *pst, int toktype, struct ts_value *val)
81 ts_set_valuef(val, atof(pst->token));
85 if(pst->token[0] == '[' || pst->token[0] == '{') {
86 char endsym = pst->token[0] + 2; /* end symbol is dist 2 from either '[' or '{' */
87 if(read_array(pst, val, endsym) == -1) {
91 fprintf(stderr, "read_node: unexpected rhs symbol: %c\n", pst->token[0]);
98 ts_set_value_str(val, pst->token);
104 static struct ts_node *read_node(struct parser *pst)
107 struct ts_node *node;
109 if(!(node = ts_alloc_node())) {
110 perror("failed to allocate treestore node");
114 while((type = next_token(pst)) == TOK_ID) {
117 if(!(id = strdup(pst->token))) {
123 if(pst->token[0] == '=') {
125 struct ts_attr *attr;
128 if(!(attr = ts_alloc_attr())) {
132 if((type = next_token(pst)) == -1) {
134 fprintf(stderr, "read_node: unexpected EOF\n");
138 if(read_value(pst, type, &attr->val) == -1) {
140 fprintf(stderr, "failed to read value\n");
144 ts_add_attr(node, attr);
146 } else if(pst->token[0] == '{') {
148 struct ts_node *child;
150 if(!(child = read_node(pst))) {
156 ts_add_child(node, child);
159 fprintf(stderr, "unexpected token: %s\n", pst->token);
164 if(type != TOK_SYM || pst->token[0] != '}') {
165 fprintf(stderr, "expected closing brace\n");
171 fprintf(stderr, "treestore read_node failed\n");
176 static int read_array(struct parser *pst, struct ts_value *tsv, char endsym)
179 struct ts_value values[32];
183 while((type = next_token(pst)) != -1) {
184 ts_init_value(values + nval);
185 if(read_value(pst, type, values + nval) == -1) {
191 ts_destroy_value(values + nval);
194 type = next_token(pst);
195 if(!(type == TOK_SYM && (pst->token[0] == ',' || pst->token[0] == endsym))) {
196 fprintf(stderr, "read_array: expected comma or end symbol ('%c')\n", endsym);
199 if(pst->token[0] == endsym) {
200 break; /* we're done */
208 res = ts_set_value_arr(tsv, nval, values);
210 for(i=0; i<nval; i++) {
211 ts_destroy_value(values + i);
216 static int nextchar(struct parser *pst)
220 if(pst->nextc >= 0) {
224 if(pst->io->read(&c, 1, pst->io->data) < 1) {
231 static void ungetchar(char c, struct parser *pst)
233 assert(pst->nextc == -1);
237 static int next_token(struct parser *pst)
241 DYNARR_CLEAR(pst->token);
243 /* skip whitespace */
244 while((c = nextchar(pst)) != -1) {
245 if(c == '#') { /* skip to end of line */
246 while((c = nextchar(pst)) != -1 && c != '\n');
247 if(c == -1) return -1;
249 if(!isspace(c)) break;
250 if(c == '\n') ++pst->nline;
252 if(c == -1) return -1;
254 DYNARR_STRPUSH(pst->token, c);
256 if(isdigit(c) || c == '-' || c == '+') {
257 /* token is a number */
259 while((c = nextchar(pst)) != -1 &&
260 (isdigit(c) || (c == '.' && !found_dot))) {
261 DYNARR_STRPUSH(pst->token, c);
262 if(c == '.') found_dot = 1;
264 if(c != -1) ungetchar(c, pst);
268 /* token is an identifier */
269 while((c = nextchar(pst)) != -1 && (isalnum(c) || c == '_')) {
270 DYNARR_STRPUSH(pst->token, c);
272 if(c != -1) ungetchar(c, pst);
276 /* token is a string constant, remove the opening quote */
277 DYNARR_STRPOP(pst->token);
278 while((c = nextchar(pst)) != -1 && c != '"') {
279 DYNARR_STRPUSH(pst->token, c);
280 if(c == '\n') ++pst->nline;
290 int ts_text_save(struct ts_node *tree, struct ts_io *io)
294 struct ts_attr *attr;
295 int lvl = tree_level(tree);
296 int sz, inline_attr, res = -1;
298 if(!(buf = malloc(lvl + strlen(tree->name) + 4))) {
299 perror("ts_text_save failed to allocate buffer");
303 if(tree->child_list || (tree->attr_list && tree->attr_list->next)) {
309 sz = sprintf(buf, "%s%s {", indent(lvl), tree->name);
314 if(io->write(buf, sz, io->data) < sz) {
318 attr = tree->attr_list;
320 if(print_attr(attr, io, inline_attr ? -1 : lvl) == -1) {
326 c = tree->child_list;
328 if(ts_text_save(c, io) == -1) {
335 sz = sprintf(buf, "}\n");
337 sz = sprintf(buf, "%s}\n", indent(lvl));
339 if(io->write(buf, sz, io->data) < sz) {
348 static int print_attr(struct ts_attr *attr, struct ts_io *io, int level)
353 if(!(val = value_to_str(&attr->val))) {
357 sz = (level >= 0 ? level : 0) + strlen(attr->name) + ts_dynarr_size(val) + 5;
358 if(!(buf = malloc(sz))) {
359 perror("print_attr: failed to allocate name buffer");
364 sz = sprintf(buf, "%s%s = %s\n", indent(level + 1), attr->name, val);
366 sz = sprintf(buf, " %s = %s ", attr->name, val);
368 if(io->write(buf, sz, io->data) < sz) {
378 static char *append_dynstr(char *dest, char *s)
381 DYNARR_STRPUSH(dest, *s++);
386 static char *value_to_str(struct ts_value *value)
392 if(!(str = ts_dynarr_alloc(0, 1))) {
396 switch(value->type) {
398 sprintf(buf, "%g", value->fnum);
399 str = append_dynstr(str, buf);
403 DYNARR_STRPUSH(str, '[');
404 for(i=0; i<value->vec_size; i++) {
406 sprintf(buf, "%g", value->vec[i]);
408 sprintf(buf, ", %g", value->vec[i]);
410 str = append_dynstr(str, buf);
412 DYNARR_STRPUSH(str, ']');
416 DYNARR_STRPUSH(str, '[');
417 for(i=0; i<value->array_size; i++) {
419 str = append_dynstr(str, ", ");
421 if(!(valstr = value_to_str(value->array + i))) {
425 str = append_dynstr(str, valstr);
426 ts_dynarr_free(valstr);
428 DYNARR_STRPUSH(str, ']');
432 sprintf(buf, "\"%s\"", value->str);
433 str = append_dynstr(str, buf);
439 static int tree_level(struct ts_node *n)
441 if(!n->parent) return 0;
442 return tree_level(n->parent) + 1;
445 static const char *indent(int x)
447 static const char buf[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
448 const char *end = buf + sizeof buf - 1;
449 return x > sizeof buf - 1 ? buf : end - x;
452 static const char *toktypestr(int type)