static svn_error_t * unparse_implicit_length(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "unparse implicit-length atoms"; if (msg_only) return SVN_NO_ERROR; /* Unparse and check every single-byte implicit-length atom. */ { int byte; for (byte = 0; byte < 256; byte++) if (skel_is_name( (apr_byte_t)byte)) { svn_stringbuf_t *str = get_empty_string(pool); char buf = (char)byte; svn_skel_t *skel = build_atom(1, &buf, pool); str = svn_skel__unparse(skel, pool); if (! (str && str->len == 1 && str->data[0] == (char)byte)) return fail(pool, "incorrectly unparsed single-byte " "implicit-length atom"); } } return SVN_NO_ERROR; }
static svn_error_t * unparse_list(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "unparse lists"; if (msg_only) return SVN_NO_ERROR; /* Make a list of all the single-byte implicit-length atoms. */ { svn_stringbuf_t *str = get_empty_string(pool); int byte; svn_skel_t *list = empty(pool); svn_skel_t *reparsed, *elt; for (byte = 0; byte < 256; byte++) if (skel_is_name( (apr_byte_t)byte)) { char buf = byte; add(build_atom(1, &buf, pool), list); } /* Unparse that, parse it again, and see if we got the same thing back. */ str = svn_skel__unparse(list, pool); reparsed = svn_skel__parse(str->data, str->len, pool); if (! reparsed || reparsed->is_atom) return fail(pool, "result is syntactically misformed, or not a list"); if (! skel_equal(list, reparsed)) return fail(pool, "unparsing and parsing didn't preserve contents"); elt = reparsed->children; for (byte = 255; byte >= 0; byte--) if (skel_is_name( (apr_byte_t)byte)) { if (! (elt && elt->is_atom && elt->len == 1 && elt->data[0] == byte)) return fail(pool, "bad element"); /* Verify that each element's data falls within the string. */ if (elt->data < str->data || elt->data + elt->len > str->data + str->len) return fail(pool, "bad element"); elt = elt->next; } /* We should have reached the end of the list at this point. */ if (elt) return fail(pool, "list too long"); } /* Make a list of lists. */ { svn_stringbuf_t *str = get_empty_string(pool); svn_skel_t *top = empty(pool); svn_skel_t *reparsed; int i; for (i = 0; i < 10; i++) { svn_skel_t *middle = empty(pool); int j; for (j = 0; j < 10; j++) { char buf[10]; apr_size_t k; int val; /* Make some interesting atom, containing lots of binary characters. */ val = i * 10 + j; for (k = 0; k < sizeof(buf); k++) { buf[k] = val; val += j; } add(build_atom(sizeof(buf), buf, pool), middle); } add(middle, top); } str = svn_skel__unparse(top, pool); reparsed = svn_skel__parse(str->data, str->len, pool); if (! skel_equal(top, reparsed)) return fail(pool, "failed to reparse list of lists"); } return SVN_NO_ERROR; }
swexp_list_node *parse_s_expr(parser *p, char opening_brace) { char c; swexp_list_node fakehead, *tail = &fakehead; fakehead.next = NULL; fakehead.content = NULL; fakehead.type = UNDEFINED; char closing_brace = brace_pair(opening_brace); while ((c = pgetc(p)) != EOF && !is_closing_brace(c)) { // if we encounter a comment in any state, strip it out IGNORE_COMMENTS() switch (p->state) { case SKIP_SPACE: if (is_space(c) || is_newline(c)) { // do nothing if it is space or newline } else if (is_opening_brace(c)) { // parse the parenthesized s expression into a list // and append it to the thing swexp_list_node *list = malloc(sizeof(swexp_list_node)); list->type = LIST; list->next = NULL; list->location = NULL; list->content = parse_s_expr(p, c); tail->next = list; tail = list; } else { // step back and start collecting the atom prewind(p, c); begin_atom(p); } break; case COLLECTING_ATOM: if (is_space(c) || is_newline(c)) { prewind(p, c); tail->next = close_atom(p); tail = tail->next; } else if (is_opening_brace(c)) { swexp_list_node *node = close_atom(p); node->next = parse_s_expr(p, c); tail->next = listof(node); tail = chain_tail(tail); } else { build_atom(p, c); } break; default: printf("unexpected state %d in parse_s_expr", p->state); exit(1); } } if (is_closing_brace(c) && c != closing_brace) { printf("mismatched braces in s expression\n"); exit(1); } if (p->state == COLLECTING_ATOM) { tail->next = close_atom(p); } if (c == EOF) { printf("unexpected EOF while parsing s expression\n"); exit(1); } p->state = SKIP_SPACE; return fakehead.next; }
swexp_list_node *parse_line(parser *p) { // parses a line of text, starting at a non-whitespace char char c; // build a list of expressions started by this // list head on the stack. swexp_list_node head, *tail; head.next = NULL; head.content = NULL; head.type = UNDEFINED; tail = &head; p->state = SKIP_SPACE; while ((c = pgetc(p)) != EOF && !is_newline(c) && !is_closing_brace(c)) { // if we encounter a comment in any state, strip it out IGNORE_COMMENTS() switch (p->state) { case COLLECTING_ATOM: if (is_space(c)) { // end atom tail->next = close_atom(p); tail = tail->next; prewind(p, c); } else if (is_opening_brace(c)) { swexp_list_node *bracehead = close_atom(p); swexp_list_node *bracecontent = parse_s_expr(p, c); bracehead->next = bracecontent; tail->next = listof(bracehead); tail = chain_tail(tail); } else { // continue to build item build_atom(p, c); } break; case SKIP_SPACE: if (is_opening_brace(c)) { swexp_list_node *brace = parse_s_expr(p, c); tail->next = brace; tail = chain_tail(tail); } else if (!is_space(c)) { begin_atom(p); prewind(p, c); } break; default: printf("unexpected state %d in parse_line\n", p->state); exit(1); } } if (is_newline(c)) { p->indentation = 0; } if (is_closing_brace(c)) { printf("encountered unmatched closing brace\n"); exit(1); } // close ongoing capture if (p->state == COLLECTING_ATOM) { tail->next = close_atom(p); } // if the number of collected atoms is more than one, // make it a list and return it if (chain_len(head.next) > 1) { swexp_list_node *listhead = malloc(sizeof(swexp_list_node)); listhead->type = LIST; listhead->next = NULL; listhead->content = head.next; listhead->location = NULL; return listhead; } else { return head.next; } }