varstr * varstr_fromstr(char *str) { varstr * v = varstr_new(strlen(str)); return varstr_cat(v, str); }
struct linereader * linereader_new( void ) { struct linereader *tp; tp = ( struct linereader * ) malloc( sizeof ( struct linereader ) ); if ( _IS_NULL( tp ) ) return NULL; tp->in = stdin; /* default */ tp->text = varstr_new( ); return tp; }
struct token token_stream_read(struct token_stream * ts) { if(ts->end) return token_new(TOKEN_TYPE_END); enum states{ READ_NEXT = 0, SCAN, SCAN_ERR, BUILD_SECTION, BUILD_SECTION1, BUILD_SECTION_END, BUILD_NAME, BUILD_NAME1, BUILD_NAME_END, BUILD_ASSIGNMENT, BUILD_STRING, BUILD_STRING1, BUILD_STRING_END, BUILD_COMMENT, BUILD_NEWLINE, BUILD_END, ERROR, SKIP_LINE, } state = ts->next_state; struct varstr * buf = varstr_new(); struct char_stream * cs = ts->cs; struct token tok; int running = 1; do switch(state){ case READ_NEXT: next_char(cs); state = SCAN; case SCAN: if(!cs->escaped) { if(cs->c == ' ' || cs->c == '\t') state = READ_NEXT; else if(cs->c == '[') state = BUILD_SECTION; else if(char_is_name(cs)) state = BUILD_NAME; else if(cs->c == '=') state = BUILD_ASSIGNMENT; else if(cs->c == '"') state = BUILD_STRING; else if(cs->c == '#') state = BUILD_COMMENT; else if(cs->c == '\n') state = BUILD_NEWLINE; else if(cs->c == EOF) state = BUILD_END; else state = SCAN_ERR; } else state = SCAN_ERR; break; case SCAN_ERR: fprintf(stderr,"next_token: " "bad token at row %d, column %d\n", cs->row, cs->col); state = SKIP_LINE; break; case BUILD_SECTION: // [section] varstr_clear(buf); tok = token_new(TOKEN_TYPE_SECTION); state = BUILD_SECTION1; case BUILD_SECTION1: next_char(cs); if(char_is_name(cs)) varstr_append(buf, cs->c); else state = BUILD_SECTION_END; break; case BUILD_SECTION_END: if(cs->c == ']' && !cs->escaped) { ts->next_state = READ_NEXT; tok.text = cstr_dup(varstr_view(buf)); running = 0; } else { fprintf(stderr, "next_token: " "bad section name at row %d, column %d, " "expected ']'\n", cs->row, cs->col); state = ERROR; } break; case BUILD_NAME: // name tok = token_new(TOKEN_TYPE_NAME); varstr_clear(buf); varstr_append(buf, cs->c); state = BUILD_NAME1; case BUILD_NAME1: next_char(cs); if(char_is_name(cs)) varstr_append(buf, cs->c); else state = BUILD_NAME_END; break; case BUILD_NAME_END: ts->next_state = SCAN; tok.text = cstr_dup(varstr_view(buf)); running = 0; break; case BUILD_ASSIGNMENT: // = tok = token_new(TOKEN_TYPE_ASSIGNMENT); ts->next_state = READ_NEXT; running = 0; break; case BUILD_STRING: /* "multi line string with escape /"/n" */ tok = token_new(TOKEN_TYPE_STRING); varstr_clear(buf); state = BUILD_STRING1; case BUILD_STRING1: next_char(cs); if(cs->c == EOF) state = BUILD_STRING_END; else if(cs->c == '"' && !cs->escaped) state = BUILD_STRING_END; else varstr_append(buf, cs->c); break; case BUILD_STRING_END: if(cs->c == '"' && !cs->escaped) { ts->next_state = READ_NEXT; tok.text = cstr_dup(varstr_view(buf)); running = 0; } else if(cs->c == EOF) { fprintf(stderr, "next_token" "bad string at row %d, column %d, " "expected '\"'\n", cs->row, cs->col); state = ERROR; } break; case BUILD_COMMENT: // # comment state = SKIP_LINE; break; case BUILD_NEWLINE: tok = token_new(TOKEN_TYPE_NEWLINE); ts->next_state = READ_NEXT; running = 0; break; case BUILD_END: tok = token_new(TOKEN_TYPE_NEWLINE); ts->end = 1; running = 0; break; case ERROR: state = SKIP_LINE; case SKIP_LINE: if(cs->c == '\n' && !cs->escaped) state = BUILD_NEWLINE; else if(cs->c == EOF) state = BUILD_END; else next_char(cs); break; }while(running); varstr_del(buf); return tok; }