+ next_char();
+ }
+
+ return value;
+}
+
+static int parse_escape_sequence(void)
+{
+ eat('\\');
+
+ int ec = c;
+ next_char();
+
+ switch(ec) {
+ case '"': return '"';
+ case '\'': return'\'';
+ case '\\': return '\\';
+ case '?': return '\?';
+ case 'a': return '\a';
+ case 'b': return '\b';
+ case 'f': return '\f';
+ case 'n': return '\n';
+ case 'r': return '\r';
+ case 't': return '\t';
+ case 'v': return '\v';
+ case 'x':
+ return parse_hex_sequence();
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ return parse_octal_sequence();
+ case EOF:
+ parse_error("reached end of file while parsing escape sequence");
+ return EOF;
+ default:
+ parse_error("unknown escape sequence");
+ return EOF;
+ }
+}
+
+const char *concat_strings(const char *s1, const char *s2)
+{
+ size_t len1 = strlen(s1);
+ size_t len2 = strlen(s2);
+
+ char *concat = obstack_alloc(&symbol_obstack, len1 + len2 + 1);
+ memcpy(concat, s1, len1);
+ memcpy(concat + len1, s2, len2 + 1);
+
+ const char *result = strset_insert(&stringset, concat);
+ if(result != concat) {
+ obstack_free(&symbol_obstack, concat);