1 /* Yash: yet another shell */
2 /* parser.h: syntax parser */
3 /* (C) 2007-2018 magicant */
5 /* This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 /* Limitation: Don't include "parser.h" and <termios.h> at a time
20 * because identifiers prefixed "c_" conflict. */
31 /********** Parse Tree Structures **********/
33 /* Basically, parse tree structure elements constitute linked lists.
34 * For each element, the `next' member points to the next element. */
37 typedef struct and_or_T {
38 struct and_or_T *next;
39 struct pipeline_T *ao_pipelines; /* pipelines in this and/or list */
42 /* ao_async: indicates this and/or list is postfixed by "&", which means the
43 * list is executed asynchronously. */
46 typedef struct pipeline_T {
47 struct pipeline_T *next;
48 struct command_T *pl_commands; /* commands in this pipeline */
49 _Bool pl_neg, pl_cond;
51 /* pl_neg: indicates this pipeline is prefix by "!", in which case the exit
52 * status of the pipeline is inverted.
53 * pl_cond: true if prefixed by "&&", false by "||". Ignored for the first
54 * pipeline in an and/or list. */
56 /* type of command_T */
58 CT_SIMPLE, /* simple command */
59 CT_GROUP, /* command group enclosed by { } */
60 CT_SUBSHELL, /* subshell command group enclosed by ( ) */
61 CT_IF, /* if command */
62 CT_FOR, /* for command */
63 CT_WHILE, /* while/until command */
64 CT_CASE, /* case command */
65 #if YASH_ENABLE_DOUBLE_BRACKET
66 CT_BRACKET, /* double-bracket command */
68 CT_FUNCDEF, /* function definition */
71 /* command in a pipeline */
72 typedef struct command_T {
73 struct command_T *next;
76 unsigned long c_lineno; /* line number */
77 struct redir_T *c_redirs; /* redirections */
80 struct assign_T *assigns; /* assignments */
81 void **words; /* command name and arguments */
83 struct and_or_T *subcmds; /* contents of command group */
84 struct ifcommand_T *ifcmds; /* contents of if command */
86 wchar_t *forname; /* loop variable of for loop */
87 void **forwords; /* words assigned to loop variable */
88 struct and_or_T *forcmds; /* commands executed in for loop */
91 _Bool whltype; /* 1 for while loop, 0 for until */
92 struct and_or_T *whlcond; /* loop condition of while/until loop */
93 struct and_or_T *whlcmds; /* commands executed in loop */
96 struct wordunit_T *casword; /* word compared to case patterns */
97 struct caseitem_T *casitems; /* pairs of patterns and commands */
99 struct dbexp_T *dbexp; /* double-bracket command expression */
101 struct wordunit_T *funcname; /* name of function */
102 struct command_T *funcbody; /* body of function */
106 #define c_assigns c_content.simplecommand.assigns
107 #define c_words c_content.simplecommand.words
108 #define c_subcmds c_content.subcmds
109 #define c_ifcmds c_content.ifcmds
110 #define c_forname c_content.forloop.forname
111 #define c_forwords c_content.forloop.forwords
112 #define c_forcmds c_content.forloop.forcmds
113 #define c_whltype c_content.whileloop.whltype
114 #define c_whlcond c_content.whileloop.whlcond
115 #define c_whlcmds c_content.whileloop.whlcmds
116 #define c_casword c_content.casecommand.casword
117 #define c_casitems c_content.casecommand.casitems
118 #define c_dbexp c_content.dbexp
119 #define c_funcname c_content.funcdef.funcname
120 #define c_funcbody c_content.funcdef.funcbody
121 /* `c_words' and `c_forwords' are NULL-terminated arrays of pointers to
122 * `wordunit_T' that are cast to `void *'.
123 * If `c_forwords' is NULL, the for loop doesn't have the "in" clause.
124 * If `c_forwords[0]' is NULL, the "in" clause exists and is empty. */
126 /* condition and commands of an if command */
127 typedef struct ifcommand_T {
128 struct ifcommand_T *next;
129 struct and_or_T *ic_condition; /* condition */
130 struct and_or_T *ic_commands; /* commands */
132 /* For an "else" clause, `next' and `ic_condition' are NULL. */
134 /* patterns and commands of a case command */
135 typedef struct caseitem_T {
136 struct caseitem_T *next;
137 void **ci_patterns; /* patterns to do matching */
138 struct and_or_T *ci_commands; /* commands executed if match succeeds */
140 /* `ci_patterns' is a NULL-terminated array of pointers to `wordunit_T' that are
141 * cast to `void *'. */
143 /* type of dbexp_T */
145 DBE_OR, /* the "||" operator, two operand expressions */
146 DBE_AND, /* the "&&" operator, two operand expressions */
147 DBE_NOT, /* the "!" operator, one operand expression */
148 DBE_UNARY, /* -f, -n, etc., one operand word */
149 DBE_BINARY, /* -eq, =, etc., two operand words */
150 DBE_STRING, /* single string primary, one operand word */
153 /* operand of expression in double-bracket command */
154 typedef union dboperand_T {
155 struct dbexp_T *subexp;
156 struct wordunit_T *word;
159 /* expression in double-bracket command */
160 typedef struct dbexp_T {
163 dboperand_T lhs, rhs;
165 /* `operator' is NULL for non-primary expressions */
166 /* `lhs' is NULL for one-operand expressions */
168 /* embedded command */
169 typedef struct embedcmd_T {
173 struct and_or_T *preparsed;
177 /* type of wordunit_T */
179 WT_STRING, /* string (including quotes) */
180 WT_PARAM, /* parameter expansion */
181 WT_CMDSUB, /* command substitution */
182 WT_ARITH, /* arithmetic expansion */
185 /* element of a word subject to expansion */
186 typedef struct wordunit_T {
187 struct wordunit_T *next;
188 wordunittype_T wu_type;
190 wchar_t *string; /* string (including quotes) */
191 struct paramexp_T *param; /* parameter expansion */
192 struct embedcmd_T cmdsub; /* command substitution */
193 struct wordunit_T *arith; /* expression for arithmetic expansion */
196 #define wu_string wu_value.string
197 #define wu_param wu_value.param
198 #define wu_cmdsub wu_value.cmdsub
199 #define wu_arith wu_value.arith
200 /* In arithmetic expansion, the expression is subject to parameter expansion
201 * before it is parsed. So `wu_arith' is of type `wordunit_T *'. */
203 /* type of paramexp_T */
205 PT_NONE, /* normal */
206 PT_MINUS, /* ${name-subst} */
207 PT_PLUS, /* ${name+subst} */
208 PT_ASSIGN, /* ${name=subst} */
209 PT_ERROR, /* ${name?subst} */
210 PT_MATCH, /* ${name#match}, ${name%match} */
211 PT_SUBST, /* ${name/match/subst} */
212 PT_MASK = (1 << 3) - 1,
213 PT_NUMBER = 1 << 3, /* ${#name} (only valid for PT_NONE) */
214 PT_COLON = 1 << 4, /* ${name:-subst}, ${name:+subst}, etc. */
215 PT_MATCHHEAD = 1 << 5, /* only matches at the beginning of a string */
216 PT_MATCHTAIL = 1 << 6, /* only matches at the end of a string */
217 PT_MATCHLONGEST = 1 << 7, /* match as long as possible */
218 PT_SUBSTALL = 1 << 8, /* substitute all the match */
219 PT_NEST = 1 << 9, /* have nested expn. like ${${VAR#foo}%bar} */
221 /* type COLON MATCHH MATCHT MATCHL SUBSTA
230 * ${n#m} MATCH no yes no no no
231 * ${n##m} MATCH no yes no yes no
232 * ${n%m} MATCH no no yes no no
233 * ${n%%m} MATCH no no yes yes no
234 * ${n/m/s} SUBST no no no yes no
235 * ${n/#m/s} SUBST no yes no yes no
236 * ${n/%m/s} SUBST no no yes yes no
237 * ${n//m/s} SUBST no no no yes yes
238 * ${n:/m/s} SUBST yes yes yes
240 * PT_SUBST and PT_NEST is beyond POSIX. */
242 /* parameter expansion */
243 typedef struct paramexp_T {
244 paramexptype_T pe_type;
247 struct wordunit_T *nest;
249 struct wordunit_T *pe_start, *pe_end;
250 struct wordunit_T *pe_match, *pe_subst;
252 #define pe_name pe_value.name
253 #define pe_nest pe_value.nest
254 /* pe_name: name of parameter
255 * pe_nest: nested parameter expansion
256 * pe_start: index of the first element in the range
257 * pe_end: index of the last element in the range
258 * pe_match: word to be matched with the value of the parameter
259 * pe_subst: word to to substitute the matched string with
260 * `pe_start' and `pe_end' is NULL if the indices are not specified.
261 * `pe_match' and `pe_subst' may be NULL to denote an empty string. */
263 /* type of assignment */
269 typedef struct assign_T {
270 struct assign_T *next;
274 struct wordunit_T *scalar;
276 } a_value; /* value to assign */
278 #define a_scalar a_value.scalar
279 #define a_array a_value.array
280 /* `a_scalar' may be NULL to denote an empty string.
281 * `a_array' is an array of pointers to `wordunit_T'. */
283 /* type of redirection */
285 RT_INPUT, /* <file */
286 RT_OUTPUT, /* >file */
287 RT_CLOBBER, /* >|file */
288 RT_APPEND, /* >>file */
289 RT_INOUT, /* <>file */
291 RT_DUPOUT, /* >&fd */
294 RT_HERERT, /* <<-END */
295 RT_HERESTR, /* <<<str */
296 RT_PROCIN, /* <(command) */
297 RT_PROCOUT, /* >(command) */
301 typedef struct redir_T {
302 struct redir_T *next;
304 int rd_fd; /* file descriptor to redirect */
306 struct wordunit_T *filename;
308 wchar_t *hereend; /* token indicating end of here-document */
309 struct wordunit_T *herecontent; /* contents of here-document */
311 struct embedcmd_T command;
314 #define rd_filename rd_value.filename
315 #define rd_hereend rd_value.heredoc.hereend
316 #define rd_herecontent rd_value.heredoc.herecontent
317 #define rd_command rd_value.command
318 /* For example, for "2>&1", `rd_type' = RT_DUPOUT, `rd_fd' = 2 and
319 * `rd_filename' = "1".
320 * For RT_HERERT, all the lines in `rd_herecontent' have the leading tabs
321 * already removed. If `rd_hereend' is quoted, `rd_herecontent' is a single
322 * word unit of type WT_STRING, since no parameter expansions are performed.
323 * Anyway `rd_herecontent' is expanded by calling `expand_string' with `esc'
324 * argument being true. */
327 /********** Interface to Parsing Routines **********/
329 /* Holds parameters that affect the behavior of parsing. */
330 typedef struct parseparam_T {
331 _Bool print_errmsg; /* print error messages? */
332 _Bool enable_verbose; /* echo input if `shopt_verbose' is true? */
333 _Bool enable_alias; /* perform alias substitution? */
334 const char *filename; /* the input filename, which may be NULL */
335 unsigned long lineno; /* line number, which should be initialized to 1 */
336 inputfunc_T *input; /* input function */
337 void *inputinfo; /* pointer passed to the input function */
338 _Bool interactive; /* input is interactive? */
339 inputresult_T lastinputresult; /* last return value of input function */
341 /* If `interactive' is true, `input' is `input_interactive' and `inputinfo' is a
342 * pointer to a `struct input_interactive_info_T' object.
343 * Note that input may not be from a terminal even if `interactive' is true. */
345 typedef enum parseresult_T {
346 PR_OK, PR_EOF, PR_SYNTAX_ERROR, PR_INPUT_ERROR,
350 extern parseresult_T read_and_parse(
351 parseparam_T *info, and_or_T **restrict resultp)
352 __attribute__((nonnull,warn_unused_result));
354 extern _Bool parse_string(parseparam_T *info, wordunit_T **restrict resultp)
355 __attribute__((nonnull,warn_unused_result));
358 /********** Auxiliary Functions **********/
360 extern _Bool is_portable_name_char(wchar_t c)
361 __attribute__((const));
362 extern _Bool is_name_char(wchar_t c)
363 __attribute__((pure));
364 extern _Bool is_name(const wchar_t *s)
365 __attribute__((pure));
366 extern _Bool is_keyword(const wchar_t *s)
367 __attribute__((nonnull,pure));
368 extern _Bool is_token_delimiter_char(wchar_t c)
369 __attribute__((pure));
372 /********** Functions That Convert Parse Trees into Strings **********/
374 extern wchar_t *pipelines_to_wcs(const pipeline_T *pipelines)
375 __attribute__((malloc,warn_unused_result));
376 extern wchar_t *command_to_wcs(const command_T *command, _Bool multiline)
377 __attribute__((malloc,warn_unused_result));
380 /********** Functions That Free/Duplicate Parse Trees **********/
382 extern void andorsfree(and_or_T *a);
383 static inline command_T *comsdup(command_T *c);
384 extern void comsfree(command_T *c);
385 extern void wordfree(wordunit_T *w);
386 extern void paramfree(paramexp_T *p);
389 /* Duplicates the specified command (virtually). */
390 command_T *comsdup(command_T *c)
392 refcount_increment(&c->refcount);
397 #endif /* YASH_PARSER_H */
400 /* vim: set ts=8 sts=4 sw=4 et tw=80: */