- if(*input == '{') {
- /* This is a bracketed argument. We'll walk over it counting
- * braces to figure out where the end is. */
- ++input;
- argument_start = input;
- argument_start_line = line;
- while(input < end && (*input != '}' || braces > 0)) {
- switch(*input++) {
- case '{': ++braces; break;
- case '}': --braces; break;
- case '\n': ++line; break;
- }
- }
- /* If we run out of input without seeing a '}' that's an error */
- if(input >= end)
- fatal(0, "%s:%d: unterminated expansion '%.*s'",
+ /* It's a full expansion */
+ ++input;
+ e = xmalloc(sizeof *e);
+ e->next = 0;
+ e->filename = filename;
+ e->line = line;
+ e->type = MX_EXPANSION;
+ /* Collect the expansion name. Expansion names start with an alnum and
+ * consist of alnums and '-'. We don't permit whitespace between the '@'
+ * and the name. */
+ dynstr_init(d);
+ if(input == end)
+ fatal(0, "%s:%d: invalid expansion syntax (truncated)",
+ filename, e->line);
+ if(!isalnum((unsigned char)*input))
+ fatal(0, "%s:%d: invalid expansion syntax (unexpected %#x)",
+ filename, e->line, (unsigned char)*input);
+ while(input < end && (isalnum((unsigned char)*input) || *input == '-'))
+ dynstr_append(d, *input++);
+ dynstr_terminate(d);
+ e->name = d->vec;
+ /* See what the bracket character is */
+ obracket = next_non_whitespace(input, end);
+ switch(obracket) {
+ case '(': cbracket = ')'; break;
+ case '[': cbracket = ']'; break;
+ case '{': cbracket = '}'; break;
+ default: cbracket = obracket = -1; break; /* no arguments */
+ }
+ mx_node_vector_init(v);
+ if(obracket >= 0) {
+ /* Gather up arguments */
+ while(next_non_whitespace(input, end) == obracket) {
+ while(isspace((unsigned char)*input)) {
+ if(*input == '\n')
+ ++line;
+ ++input;
+ }
+ ++input; /* the bracket */
+ braces = 0;
+ /* Find the end of the argument */
+ argument_start = input;
+ argument_start_line = line;
+ while(input < end && (*input != cbracket || braces > 0)) {
+ const int c = *input++;
+
+ if(c == obracket)
+ ++braces;
+ else if(c == cbracket)
+ --braces;
+ else if(c == '\n')
+ ++line;
+ }
+ if(input >= end) {
+ /* We ran out of input without encountering a balanced cbracket */
+ fatal(0, "%s:%d: unterminated expansion argument '%.*s'",