14 enum { TOK_SYM, TOK_ID, TOK_NUM, TOK_STR };
16 static struct ts_node *read_node(struct parser *pstate);
17 static int read_array(struct parser *pstate, struct ts_value *tsv, char endsym);
18 static int next_token(struct parser *pstate);
20 static void print_attr(struct ts_attr *attr, FILE *fp, int level);
21 static void print_value(struct ts_value *value, FILE *fp);
22 static int tree_level(struct ts_node *n);
23 static const char *indent(int x);
24 static const char *toktypestr(int type);
26 #define EXPECT(type) \
28 if(next_token(pst) != (type)) { \
29 fprintf(stderr, "expected %s token\n", toktypestr(type)); \
34 #define EXPECT_SYM(c) \
36 if(next_token(pst) != TOK_SYM || pst->token[0] != (c)) { \
37 fprintf(stderr, "expected symbol: %c\n", c); \
43 struct ts_node *ts_text_load(FILE *fp)
46 struct parser pstate, *pst = &pstate;
47 struct ts_node *node = 0;
51 if(!(pstate.token = dynarr_alloc(0, 1))) {
52 perror("failed to allocate token string");
57 if(!(root_name = strdup(pst->token))) {
58 perror("failed to allocate root node name");
59 dynarr_free(pst->token);
63 if(!(node = read_node(pst))) {
64 dynarr_free(pst->token);
67 node->name = root_name;
70 dynarr_free(pst->token);
74 static int read_value(struct parser *pst, int toktype, struct ts_value *val)
78 ts_set_valuef(val, atof(pst->token));
82 if(pst->token[0] == '[' || pst->token[0] == '{') {
83 char endsym = pst->token[0] + 2; /* end symbol is dist 2 from either '[' or '{' */
84 if(read_array(pst, val, endsym) == -1) {
88 fprintf(stderr, "read_node: unexpected rhs symbol: %c\n", pst->token[0]);
95 ts_set_value_str(val, pst->token);
101 static struct ts_node *read_node(struct parser *pst)
104 struct ts_node *node;
106 if(!(node = ts_alloc_node())) {
107 perror("failed to allocate treestore node");
111 while((type = next_token(pst)) == TOK_ID) {
114 if(!(id = strdup(pst->token))) {
120 if(pst->token[0] == '=') {
122 struct ts_attr *attr;
125 if(!(attr = ts_alloc_attr())) {
129 if((type = next_token(pst)) == -1) {
131 fprintf(stderr, "read_node: unexpected EOF\n");
135 if(read_value(pst, type, &attr->val) == -1) {
137 fprintf(stderr, "failed to read value\n");
141 ts_add_attr(node, attr);
143 } else if(pst->token[0] == '{') {
145 struct ts_node *child;
147 if(!(child = read_node(pst))) {
153 ts_add_child(node, child);
156 fprintf(stderr, "unexpected token: %s\n", pst->token);
161 if(type != TOK_SYM || pst->token[0] != '}') {
162 fprintf(stderr, "expected closing brace\n");
168 fprintf(stderr, "treestore read_node failed\n");
173 static int read_array(struct parser *pst, struct ts_value *tsv, char endsym)
176 struct ts_value values[32];
180 while((type = next_token(pst)) != -1) {
181 ts_init_value(values + nval);
182 if(read_value(pst, type, values + nval) == -1) {
188 ts_destroy_value(values + nval);
191 type = next_token(pst);
192 if(!(type == TOK_SYM && (pst->token[0] == ',' || pst->token[0] == endsym))) {
193 fprintf(stderr, "read_array: expected comma or end symbol ('%c')\n", endsym);
196 if(pst->token[0] == endsym) {
197 break; /* we're done */
205 res = ts_set_value_arr(tsv, nval, values);
207 for(i=0; i<nval; i++) {
208 ts_destroy_value(values + i);
213 static int next_token(struct parser *pst)
217 DYNARR_CLEAR(pst->token);
219 /* skip whitespace */
220 while((c = fgetc(pst->fp)) != -1) {
221 if(c == '#') { /* skip to end of line */
222 while((c = fgetc(pst->fp)) != -1 && c != '\n');
223 if(c == -1) return -1;
225 if(!isspace(c)) break;
226 if(c == '\n') ++pst->nline;
228 if(c == -1) return -1;
230 DYNARR_STRPUSH(pst->token, c);
232 if(isdigit(c) || c == '-' || c == '+') {
233 /* token is a number */
235 while((c = fgetc(pst->fp)) != -1 &&
236 (isdigit(c) || (c == '.' && !found_dot))) {
237 DYNARR_STRPUSH(pst->token, c);
238 if(c == '.') found_dot = 1;
240 if(c != -1) ungetc(c, pst->fp);
244 /* token is an identifier */
245 while((c = fgetc(pst->fp)) != -1 && (isalnum(c) || c == '_')) {
246 DYNARR_STRPUSH(pst->token, c);
248 if(c != -1) ungetc(c, pst->fp);
252 /* token is a string constant */
253 /* remove the opening quote */
254 DYNARR_STRPOP(pst->token);
255 while((c = fgetc(pst->fp)) != -1 && c != '"') {
256 DYNARR_STRPUSH(pst->token, c);
257 if(c == '\n') ++pst->nline;
267 int ts_text_save(struct ts_node *tree, FILE *fp)
270 struct ts_attr *attr;
271 int lvl = tree_level(tree);
273 fprintf(fp, "%s%s {\n", indent(lvl), tree->name);
275 attr = tree->attr_list;
277 print_attr(attr, fp, lvl);
281 c = tree->child_list;
287 fprintf(fp, "%s}\n", indent(lvl));
291 static void print_attr(struct ts_attr *attr, FILE *fp, int level)
293 fprintf(fp, "%s%s = ", indent(level + 1), attr->name);
294 print_value(&attr->val, fp);
298 static void print_value(struct ts_value *value, FILE *fp)
302 switch(value->type) {
304 fprintf(fp, "%g", value->fnum);
309 for(i=0; i<value->vec_size; i++) {
311 fprintf(fp, "%g", value->vec[i]);
313 fprintf(fp, ", %g", value->vec[i]);
321 for(i=0; i<value->array_size; i++) {
325 print_value(value->array + i, fp);
331 fprintf(fp, "\"%s\"", value->str);
335 static int tree_level(struct ts_node *n)
337 if(!n->parent) return 0;
338 return tree_level(n->parent) + 1;
341 static const char *indent(int x)
343 static const char buf[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
344 const char *end = buf + sizeof buf - 1;
345 return x > sizeof buf - 1 ? buf : end - x;
348 static const char *toktypestr(int type)