3 * Copyright (c) 2011 James Gritton
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
44 static ssize_t text2lval(size_t triml, size_t trimr, int tovar);
47 static int lineno = 1;
54 /* Whitespace or equivalent */
58 <_>\/\*([^*]|(\*+([^*\/])))*\*+\/ {
61 for (s = yytext; s < yytext + yyleng; s++)
81 /* Atomic (unquoted) strings */
82 <_,DQ>[A-Za-z0-9_!%&()\-.:<>?@\[\]^`|~]+ |
83 <_,DQ>\\(.|\n|[0-7]{1,3}|x[0-9A-Fa-f]{1,2}) |
85 (void)text2lval(0, 0, 0);
86 return instr ? STR1 : (instr = 1, STR);
89 /* Single and double quoted strings */
90 <_>'([^\'\\]|\\(.|\n))*' {
91 (void)text2lval(1, 1, 0);
92 return instr ? STR1 : (instr = 1, STR);
94 <_>\"([^"\\]|\\(.|\n))*\" |
95 <DQ>[^\"$\\]([^"\\]|\\(.|\n))*\" {
99 skip = yytext[0] == '"' ? 1 : 0;
100 atvar = text2lval(skip, 1, 1);
105 * The string has a variable inside it.
106 * Go into DQ mode to get the variable
107 * and then the rest of the string.
112 return instr ? STR1 : (instr = 1, STR);
116 /* Variables, single-word or bracketed */
117 <_,DQ>$[A-Za-z_][A-Za-z_0-9]* {
118 (void)text2lval(1, 0, 0);
119 return instr ? VAR1 : (instr = 1, VAR);
121 <_>$\{([^\n{}]|\\(.|\n))*\} |
122 <DQ>$\{([^\n\"{}]|\\(.|\n))*\} {
123 (void)text2lval(2, 1, 0);
124 return instr ? VAR1 : (instr = 1, VAR);
127 /* Partially formed bits worth complaining about */
128 <_>\/\*([^*]|(\*+([^*\/])))*\** {
129 warnx("%s line %d: unterminated comment",
133 <_>'([^\n'\\]|\\.)* |
134 <_>\"([^\n\"\\]|\\.)* {
135 warnx("%s line %d: unterminated string",
139 <_>$\{([^\n{}]|\\.)* |
140 <DQ>$\{([^\n\"{}]|\\.)* {
141 warnx("%s line %d: unterminated variable",
146 /* A hack because "<0>" rules aren't allowed */
147 <_>. return yytext[0];
156 yyerror(const char *s)
159 warnx("%s line %d: %s", cfname, lineno, s);
161 warnx("%s: unexpected EOF", cfname);
163 warnx("%s line %d: %s: %s", cfname, lineno, yytext, s);
167 * Copy string from yytext to yylval, handling backslash escapes,
168 * and optionally stopping at the beginning of a variable.
171 text2lval(size_t triml, size_t trimr, int tovar)
176 yylval.cs = d = emalloc(yyleng - trimr - triml + 1);
177 se = yytext + (yyleng - trimr);
178 for (s = yytext + triml; s < se; s++, d++) {
180 if (tovar && *s == '$') {
190 if (*s >= '0' && *s <= '7') {
192 if (s + 1 < se && s[1] >= '0' && s[1] <= '7') {
193 *d = 010 * *d + (*++s - '0');
194 if (s + 1 < se && s[1] >= '0' && s[1] <= '7')
195 *d = 010 * *d + (*++s - '0');
200 case 'a': *d = '\a'; break;
201 case 'b': *d = '\b'; break;
202 case 'f': *d = '\f'; break;
203 case 'n': *d = '\n'; break;
204 case 'r': *d = '\r'; break;
205 case 't': *d = '\t'; break;
206 case 'v': *d = '\v'; break;
207 case '\n': d--; lineno++; break;
208 default: *d = *s; break;
213 if (s[1] >= '0' && s[1] <= '9')
215 else if (s[1] >= 'A' && s[1] <= 'F')
216 *d = *++s + (0xA - 'A');
217 else if (s[1] >= 'a' && s[1] <= 'a')
218 *d = *++s + (0xa - 'a');
223 if (s[1] >= '0' && s[1] <= '9')
224 *d = *d * 0x10 + (*++s - '0');
225 else if (s[1] >= 'A' && s[1] <= 'F')
226 *d = *d * 0x10 + (*++s + (0xA - 'A'));
227 else if (s[1] >= 'a' && s[1] <= 'a')
228 *d = *d * 0x10 + (*++s + (0xa - 'a'));