OSDN Git Service

Replace INIT with DUMMY_INIT macro
[yash/yash.git] / parser.h
1 /* Yash: yet another shell */
2 /* parser.h: syntax parser */
3 /* (C) 2007-2018 magicant */
4
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.
9  * 
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.
14  * 
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/>.  */
17
18
19 /* Limitation: Don't include "parser.h" and <termios.h> at a time
20  *    because identifiers prefixed "c_" conflict. */
21
22
23 #ifndef YASH_PARSER_H
24 #define YASH_PARSER_H
25
26 #include <stddef.h>
27 #include "input.h"
28 #include "refcount.h"
29
30
31 /********** Parse Tree Structures **********/
32
33 /* Basically, parse tree structure elements constitute linked lists.
34  * For each element, the `next' member points to the next element. */
35
36 /* and/or list */
37 typedef struct and_or_T {
38     struct and_or_T   *next;
39     struct pipeline_T *ao_pipelines;  /* pipelines in this and/or list */
40     _Bool              ao_async;
41 } and_or_T;
42 /* ao_async: indicates this and/or list is postfixed by "&", which means the
43  * list is executed asynchronously. */
44
45 /* pipeline */
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;
50 } pipeline_T;
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. */
55
56 /* type of command_T */
57 typedef enum {
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 */
67 #endif
68     CT_FUNCDEF,    /* function definition */
69 } commandtype_T;
70
71 /* command in a pipeline */
72 typedef struct command_T {
73     struct command_T *next;
74     refcount_T        refcount;
75     commandtype_T     c_type;
76     unsigned long     c_lineno;   /* line number */
77     struct redir_T   *c_redirs;   /* redirections */
78     union {
79         struct {
80             struct assign_T *assigns;  /* assignments */
81             void           **words;    /* command name and arguments */
82         } simplecommand;
83         struct and_or_T     *subcmds;  /* contents of command group */
84         struct ifcommand_T  *ifcmds;   /* contents of if command */
85         struct {
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 */
89         } forloop;
90         struct {
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 */
94         } whileloop;
95         struct {
96             struct wordunit_T *casword;   /* word compared to case patterns */
97             struct caseitem_T *casitems;  /* pairs of patterns and commands */
98         } casecommand;
99         struct dbexp_T      *dbexp;    /* double-bracket command expression */
100         struct {
101             struct wordunit_T *funcname;  /* name of function */
102             struct command_T  *funcbody;  /* body of function */
103         } funcdef;
104     } c_content;
105 } command_T;
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. */
125
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 */
131 } ifcommand_T;
132 /* For an "else" clause, `next' and `ic_condition' are NULL. */
133
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 */
139 } caseitem_T;
140 /* `ci_patterns' is a NULL-terminated array of pointers to `wordunit_T' that are
141  * cast to `void *'. */
142
143 /* type of dbexp_T */
144 typedef enum {
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 */
151 } dbexptype_T;
152
153 /* operand of expression in double-bracket command */
154 typedef union dboperand_T {
155     struct dbexp_T *subexp;
156     struct wordunit_T *word;
157 } dboperand_T;
158
159 /* expression in double-bracket command */
160 typedef struct dbexp_T {
161     dbexptype_T type;
162     wchar_t *operator;
163     dboperand_T lhs, rhs;
164 } dbexp_T;
165 /* `operator' is NULL for non-primary expressions */
166 /* `lhs' is NULL for one-operand expressions */
167
168 /* embedded command */
169 typedef struct embedcmd_T {
170     _Bool is_preparsed;
171     union {
172         wchar_t         *unparsed;
173         struct and_or_T *preparsed;
174     } value;
175 } embedcmd_T;
176
177 /* type of wordunit_T */
178 typedef enum {
179     WT_STRING,  /* string (including quotes) */
180     WT_PARAM,   /* parameter expansion */
181     WT_CMDSUB,  /* command substitution */
182     WT_ARITH,   /* arithmetic expansion */
183 } wordunittype_T;
184
185 /* element of a word subject to expansion */
186 typedef struct wordunit_T {
187     struct wordunit_T *next;
188     wordunittype_T     wu_type;
189     union {
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 */
194     } wu_value;
195 } wordunit_T;
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 *'. */
202
203 /* type of paramexp_T */
204 typedef enum {
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} */
220 } paramexptype_T;
221 /*            type   COLON  MATCHH MATCHT MATCHL SUBSTA
222  * ${n-s}     MINUS   no
223  * ${n+s}     PLUS    no
224  * ${n=s}     ASSIGN  no
225  * ${n?s}     ERROR   no
226  * ${n:-s}    MINUS   yes
227  * ${n:+s}    PLUS    yes
228  * ${n:=s}    ASSIGN  yes
229  * ${n:?s}    ERROR   yes
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
239  *
240  * PT_SUBST and PT_NEST is beyond POSIX. */
241
242 /* parameter expansion */
243 typedef struct paramexp_T {
244     paramexptype_T pe_type;
245     union {
246         wchar_t           *name;
247         struct wordunit_T *nest;
248     } pe_value;
249     struct wordunit_T *pe_start, *pe_end;
250     struct wordunit_T *pe_match, *pe_subst;
251 } paramexp_T;
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. */
262
263 /* type of assignment */
264 typedef enum {
265     A_SCALAR, A_ARRAY,
266 } assigntype_T;
267
268 /* assignment */
269 typedef struct assign_T {
270     struct assign_T *next;
271     assigntype_T a_type;
272     wchar_t *a_name;
273     union {
274         struct wordunit_T *scalar;
275         void **array;          
276     } a_value;  /* value to assign */
277 } assign_T;
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'. */
282
283 /* type of redirection */
284 typedef enum {
285     RT_INPUT,    /* <file */
286     RT_OUTPUT,   /* >file */
287     RT_CLOBBER,  /* >|file */
288     RT_APPEND,   /* >>file */
289     RT_INOUT,    /* <>file */
290     RT_DUPIN,    /* <&fd */
291     RT_DUPOUT,   /* >&fd */
292     RT_PIPE,     /* >>|fd */
293     RT_HERE,     /* <<END */
294     RT_HERERT,   /* <<-END */
295     RT_HERESTR,  /* <<<str */
296     RT_PROCIN,   /* <(command) */
297     RT_PROCOUT,  /* >(command) */
298 } redirtype_T;
299
300 /* redirection */
301 typedef struct redir_T {
302     struct redir_T *next;
303     redirtype_T rd_type;
304     int rd_fd;  /* file descriptor to redirect */
305     union {
306         struct wordunit_T *filename;
307         struct {
308             wchar_t *hereend;  /* token indicating end of here-document */
309             struct wordunit_T *herecontent;  /* contents of here-document */
310         } heredoc;
311         struct embedcmd_T command;
312     } rd_value;
313 } redir_T;
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. */
325
326
327 /********** Interface to Parsing Routines **********/
328
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 */
340 } parseparam_T;
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. */
344
345 typedef enum parseresult_T {
346     PR_OK, PR_EOF, PR_SYNTAX_ERROR, PR_INPUT_ERROR,
347 } parseresult_T;
348
349
350 extern parseresult_T read_and_parse(
351         parseparam_T *info, and_or_T **restrict resultp)
352     __attribute__((nonnull,warn_unused_result));
353
354 extern _Bool parse_string(parseparam_T *info, wordunit_T **restrict resultp)
355     __attribute__((nonnull,warn_unused_result));
356
357
358 /********** Auxiliary Functions **********/
359
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));
370
371
372 /********** Functions That Convert Parse Trees into Strings **********/
373
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));
378
379
380 /********** Functions That Free/Duplicate Parse Trees **********/
381
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);
387
388
389 /* Duplicates the specified command (virtually). */
390 command_T *comsdup(command_T *c)
391 {
392     refcount_increment(&c->refcount);
393     return c;
394 }
395
396
397 #endif /* YASH_PARSER_H */
398
399
400 /* vim: set ts=8 sts=4 sw=4 et tw=80: */