| #include <stdlib.h> |
| #ifndef lint |
| #if 0 |
| static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; |
| #else |
| #if defined(__NetBSD__) && defined(__IDSTRING) |
| __IDSTRING(yyrcsid, "$NetBSD: skeleton.c,v 1.25 2003/08/07 11:17:54 agc Exp $"); |
| #endif /* __NetBSD__ && __IDSTRING */ |
| #endif /* 0 */ |
| #endif /* lint */ |
| #define YYBYACC 1 |
| #define YYMAJOR 1 |
| #define YYMINOR 9 |
| #define YYLEX yylex() |
| #define YYEMPTY -1 |
| #define yyclearin (yychar=(YYEMPTY)) |
| #define yyerrok (yyerrflag=0) |
| #define YYRECOVERING (yyerrflag!=0) |
| #define YYPREFIX "yy" |
| #line 2 "tmesh-input.y" |
| /* $Id: tmesh-input.y,v 1.4 2006/11/15 23:11:31 fredette Exp $ */ |
| |
| /* tmesh/tmesh-input.y - the tme shell scanner and parser: */ |
| |
| /* |
| * Copyright (c) 2003 Matt Fredette |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. All advertising materials mentioning features or use of this software |
| * must display the following acknowledgement: |
| * This product includes software developed by Matt Fredette. |
| * 4. The name of the author may not be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, |
| * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
| * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include <tme/common.h> |
| _TME_RCSID("$Id: tmesh-input.y,v 1.4 2006/11/15 23:11:31 fredette Exp $"); |
| |
| /* includes: */ |
| #include <tme/threads.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <ctype.h> |
| #include "tmesh-impl.h" |
| |
| /* macros: */ |
| |
| /* internal token numbers: */ |
| #define TMESH_TOKEN_UNDEF (-1) |
| #define TMESH_TOKEN_EOF (0) |
| |
| /* internal character numbers: */ |
| #define TMESH_C_EOF_SEMICOLON (TMESH_C_YIELD - 1) |
| #define TMESH_C_UNDEF (TMESH_C_EOF_SEMICOLON - 2) |
| |
| #define YYSTYPE struct tmesh_parser_value |
| #define YYDEBUG 1 |
| #define YYMAXDEPTH 10000 |
| |
| /* types: */ |
| |
| /* globals: */ |
| static tme_mutex_t _tmesh_input_mutex; |
| static struct tmesh *_tmesh_input; |
| static char **_tmesh_output; |
| static int _tmesh_input_yielding; |
| static YYSTYPE *_tmesh_input_parsed; |
| |
| /* prototypes: */ |
| static int yylex _TME_P((void)); |
| static void yyerror _TME_P((char *)); |
| static void _tmesh_scanner_in_args _TME_P((void)); |
| static void _tmesh_parser_argv_arg _TME_P((struct tmesh_parser_argv *, char *, int)); |
| |
| #line 96 "tmesh-input.c" |
| #define TMESH_TOKEN_SOURCE 257 |
| #define TMESH_TOKEN_MKDIR 258 |
| #define TMESH_TOKEN_RMDIR 259 |
| #define TMESH_TOKEN_CD 260 |
| #define TMESH_TOKEN_PWD 261 |
| #define TMESH_TOKEN_LS 262 |
| #define TMESH_TOKEN_CONNECT 263 |
| #define TMESH_TOKEN_RM 264 |
| #define TMESH_TOKEN_MV 265 |
| #define TMESH_TOKEN_COMMAND 266 |
| #define TMESH_TOKEN_LOG 267 |
| #define TMESH_TOKEN_ALIAS 268 |
| #define TMESH_TOKEN_AT 269 |
| #define TMESH_TOKEN_PATHNAME 270 |
| #define TMESH_TOKEN_ARG 271 |
| #define TMESH_TOKEN_OPTS 272 |
| #define YYERRCODE 256 |
| const short yylhs[] = { -1, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, |
| 7, 7, 8, 9, 10, 11, 12, 13, 15, 15, |
| 17, 17, 18, 18, 19, 20, 16, 16, 16, 14, |
| 14, |
| }; |
| const short yylen[] = { 2, |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 1, 1, 2, 1, 3, 3, 3, 3, 2, 4, |
| 3, 2, 3, 4, 3, 3, 4, 1, 1, 0, |
| 1, 2, 1, 2, 1, 1, 3, 5, 3, 1, |
| 0, |
| }; |
| const short yydefred[] = { 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 31, 14, 0, 1, 2, 3, 4, |
| 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, |
| 13, 28, 0, 0, 0, 0, 19, 40, 0, 0, |
| 0, 0, 0, 0, 0, 22, 36, 32, 35, 0, |
| 0, 15, 16, 17, 18, 29, 0, 21, 23, 0, |
| 25, 26, 0, 33, 0, 0, 20, 24, 27, 34, |
| 0, 0, |
| }; |
| const short yydgoto[] = { 16, |
| 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, |
| 27, 28, 33, 39, 57, 29, 30, 65, 50, 51, |
| }; |
| const short yysindex[] = { -39, |
| -46, -260, -260, -260, -260, -45, -256, -253, -260, -260, |
| -253, -253, -260, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, -41, -58, |
| 0, 0, -38, -36, -35, -34, 0, 0, -244, -32, |
| -31, -260, -56, -55, -260, 0, 0, 0, 0, -242, |
| -242, 0, 0, 0, 0, 0, -29, 0, 0, -28, |
| 0, 0, -27, 0, -238, -57, 0, 0, 0, 0, |
| -242, -238, |
| }; |
| const short yyrindex[] = { 0, |
| 0, 0, 0, 0, 0, 0, -40, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, -25, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, -45, -24, 0, 0, 0, 0, |
| 0, -23, |
| }; |
| const short yygindex[] = { 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 2, 0, 0, 29, -3, -49, -26, 0, |
| }; |
| #define YYTABLESIZE 231 |
| const short yytable[] = { 49, |
| 49, 66, 61, 62, 34, 35, 36, 43, 44, 32, |
| 41, 42, 31, 37, 45, 38, 14, 46, 41, 15, |
| 52, 72, 53, 54, 55, 56, 58, 59, 64, 67, |
| 68, 69, 70, 30, 39, 38, 40, 0, 0, 71, |
| 0, 0, 0, 60, 0, 0, 63, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 47, 0, 48, 70, 48, 48, 1, 2, 3, 4, |
| 5, 6, 7, 8, 9, 10, 11, 12, 13, 41, |
| 14, |
| }; |
| const short yycheck[] = { 58, |
| 58, 51, 59, 59, 3, 4, 5, 11, 12, 270, |
| 9, 10, 59, 59, 13, 272, 270, 59, 59, 59, |
| 59, 71, 59, 59, 59, 270, 59, 59, 271, 59, |
| 59, 59, 271, 59, 59, 59, 8, -1, -1, 66, |
| -1, -1, -1, 42, -1, -1, 45, -1, -1, -1, |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 269, -1, 271, 271, 271, 271, 256, 257, 258, 259, |
| 260, 261, 262, 263, 264, 265, 266, 267, 268, 270, |
| 270, |
| }; |
| #define YYFINAL 16 |
| #ifndef YYDEBUG |
| #define YYDEBUG 0 |
| #endif |
| #define YYMAXTOKEN 272 |
| #if YYDEBUG |
| const char * const yyname[] = { |
| "end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"':'","';'",0,0,0,0,0,0,0,0,0,0, |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"TMESH_TOKEN_SOURCE", |
| "TMESH_TOKEN_MKDIR","TMESH_TOKEN_RMDIR","TMESH_TOKEN_CD","TMESH_TOKEN_PWD", |
| "TMESH_TOKEN_LS","TMESH_TOKEN_CONNECT","TMESH_TOKEN_RM","TMESH_TOKEN_MV", |
| "TMESH_TOKEN_COMMAND","TMESH_TOKEN_LOG","TMESH_TOKEN_ALIAS","TMESH_TOKEN_AT", |
| "TMESH_TOKEN_PATHNAME","TMESH_TOKEN_ARG","TMESH_TOKEN_OPTS", |
| }; |
| const char * const yyrule[] = { |
| "$accept : command", |
| "command : command_source", |
| "command : command_mkdir", |
| "command : command_rmdir", |
| "command : command_cd", |
| "command : command_pwd", |
| "command : command_ls", |
| "command : command_connect", |
| "command : command_rm", |
| "command : command_mv", |
| "command : command_command", |
| "command : command_log", |
| "command : command_alias", |
| "command : error ';'", |
| "command : ';'", |
| "command_source : TMESH_TOKEN_SOURCE pathname ';'", |
| "command_mkdir : TMESH_TOKEN_MKDIR pathname ';'", |
| "command_rmdir : TMESH_TOKEN_RMDIR pathname ';'", |
| "command_cd : TMESH_TOKEN_CD pathname ';'", |
| "command_pwd : TMESH_TOKEN_PWD ';'", |
| "command_ls : TMESH_TOKEN_LS opts_opt pathname_opt ';'", |
| "command_connect : TMESH_TOKEN_CONNECT connection ';'", |
| "command_connect : connection ';'", |
| "command_rm : TMESH_TOKEN_RM pathname ';'", |
| "command_mv : TMESH_TOKEN_MV pathname pathname ';'", |
| "command_command : TMESH_TOKEN_COMMAND pathname_args ';'", |
| "command_log : TMESH_TOKEN_LOG pathname_args ';'", |
| "command_alias : TMESH_TOKEN_ALIAS pathname pathname ';'", |
| "pathname : TMESH_TOKEN_PATHNAME", |
| "pathname_opt : TMESH_TOKEN_PATHNAME", |
| "pathname_opt :", |
| "pathname_args : TMESH_TOKEN_PATHNAME", |
| "pathname_args : pathname_args TMESH_TOKEN_ARG", |
| "args : TMESH_TOKEN_ARG", |
| "args : args TMESH_TOKEN_ARG", |
| "colon : ':'", |
| "at : TMESH_TOKEN_AT", |
| "connection : pathname_args colon args", |
| "connection : pathname_args at args colon args", |
| "connection : pathname_args at args", |
| "opts_opt : TMESH_TOKEN_OPTS", |
| "opts_opt :", |
| }; |
| #endif |
| #ifndef YYSTYPE |
| typedef int YYSTYPE; |
| #endif |
| #ifdef YYSTACKSIZE |
| #undef YYMAXDEPTH |
| #define YYMAXDEPTH YYSTACKSIZE |
| #else |
| #ifdef YYMAXDEPTH |
| #define YYSTACKSIZE YYMAXDEPTH |
| #else |
| #define YYSTACKSIZE 10000 |
| #define YYMAXDEPTH 10000 |
| #endif |
| #endif |
| #define YYINITSTACKSIZE 200 |
| int yydebug; |
| int yynerrs; |
| int yyerrflag; |
| int yychar; |
| short *yyssp; |
| YYSTYPE *yyvsp; |
| YYSTYPE yyval; |
| YYSTYPE yylval; |
| short *yyss; |
| short *yysslim; |
| YYSTYPE *yyvs; |
| int yystacksize; |
| int yyparse(void); |
| #line 267 "tmesh-input.y" |
| |
| /* this adds a new argument to an argument vector: */ |
| static void |
| _tmesh_parser_argv_arg(struct tmesh_parser_argv *argv, char *arg, int new) |
| { |
| |
| /* if we're starting a new argv, allocate the initial vector, else |
| make sure the argv has enough room for the new argument and a |
| trailing NULL that _tmesh_command_connect will add later: */ |
| if (new) { |
| argv->tmesh_parser_argv_size = 8; |
| argv->tmesh_parser_argv_argv = |
| _tmesh_gc_new(_tmesh_input, |
| char *, |
| argv->tmesh_parser_argv_size); |
| argv->tmesh_parser_argv_argc = 0; |
| } |
| else if ((argv->tmesh_parser_argv_argc + 1) |
| >= argv->tmesh_parser_argv_size) { |
| argv->tmesh_parser_argv_size += |
| (2 |
| + (argv->tmesh_parser_argv_size >> 1)); |
| argv->tmesh_parser_argv_argv = |
| _tmesh_gc_renew(_tmesh_input, |
| char *, |
| argv->tmesh_parser_argv_argv, |
| argv->tmesh_parser_argv_size); |
| } |
| |
| /* put in the new argument: */ |
| argv->tmesh_parser_argv_argv[argv->tmesh_parser_argv_argc++] = arg; |
| } |
| |
| /* this is called by the parser when it encounters an error: */ |
| static void |
| yyerror(char *msg) |
| { |
| tme_output_append(_tmesh_output, msg); |
| _tmesh_input->tmesh_scanner.tmesh_scanner_in_args = FALSE; |
| } |
| |
| /* this is called by the parser when args can be expected: */ |
| static void |
| _tmesh_scanner_in_args(void) |
| { |
| _tmesh_input->tmesh_scanner.tmesh_scanner_in_args = TRUE; |
| } |
| |
| /* this matches a collected token: */ |
| static int |
| _tmesh_scanner_token(struct tmesh_scanner *scanner) |
| { |
| int token; |
| char *string; |
| int keep_string; |
| |
| /* if we have no collected token, return no token: */ |
| if (scanner->tmesh_scanner_token_string_size == 0 |
| || scanner->tmesh_scanner_token_string_len == 0) { |
| return (TMESH_TOKEN_UNDEF); |
| } |
| |
| /* get the collected token: */ |
| string = scanner->tmesh_scanner_token_string; |
| string[scanner->tmesh_scanner_token_string_len] = '\0'; |
| |
| /* assume we won't need to keep this string: */ |
| keep_string = FALSE; |
| |
| /* the reserved word "at" is always recognized, since it can |
| terminate a list of arguments: */ |
| if (!strcmp(string, "at")) { |
| token = TMESH_TOKEN_AT; |
| scanner->tmesh_scanner_in_args = FALSE; |
| } |
| |
| /* if we're in arguments, every other collected token is an argument: */ |
| else if (scanner->tmesh_scanner_in_args) { |
| token = TMESH_TOKEN_ARG; |
| keep_string = TRUE; |
| } |
| |
| /* otherwise, if we're not in arguments, every other collected token |
| is either a reserved word, options, or a pathname: */ |
| else { |
| if (!strcmp(string, "source")) { |
| token = TMESH_TOKEN_SOURCE; |
| } |
| else if (!strcmp(string, "cd")) { |
| token = TMESH_TOKEN_CD; |
| } |
| else if (!strcmp(string, "pwd")) { |
| token = TMESH_TOKEN_CD; |
| } |
| else if (!strcmp(string, "ls")) { |
| token = TMESH_TOKEN_LS; |
| } |
| else if (!strcmp(string, "rm")) { |
| token = TMESH_TOKEN_RM; |
| } |
| else if (!strcmp(string, "connect")) { |
| token = TMESH_TOKEN_CONNECT; |
| } |
| else if (!strcmp(string, "mkdir")) { |
| token = TMESH_TOKEN_MKDIR; |
| } |
| else if (!strcmp(string, "rmdir")) { |
| token = TMESH_TOKEN_RMDIR; |
| } |
| else if (!strcmp(string, "mv")) { |
| token = TMESH_TOKEN_MV; |
| } |
| else if (!strcmp(string, "command")) { |
| token = TMESH_TOKEN_COMMAND; |
| } |
| else if (!strcmp(string, "log")) { |
| token = TMESH_TOKEN_LOG; |
| } |
| else if (!strcmp(string, "alias")) { |
| token = TMESH_TOKEN_ALIAS; |
| } |
| else if (string[0] == '-') { |
| token = TMESH_TOKEN_OPTS; |
| keep_string = TRUE; |
| } |
| else { |
| token = TMESH_TOKEN_PATHNAME; |
| keep_string = TRUE; |
| } |
| } |
| |
| /* if we need to keep this string, put it in yylval, else recycle it: */ |
| yylval.tmesh_parser_value_token = token; |
| if (keep_string) { |
| yylval.tmesh_parser_value_strings[0] = string; |
| scanner->tmesh_scanner_token_string_size = 0; |
| } |
| else { |
| yylval.tmesh_parser_value_strings[0] = NULL; |
| scanner->tmesh_scanner_token_string_len = 0; |
| } |
| |
| return (token); |
| } |
| |
| /* our scanner: */ |
| int |
| yylex(void) |
| { |
| struct tmesh_scanner *scanner; |
| struct tmesh_io_stack *stack; |
| struct tmesh_io *source; |
| int token, c; |
| |
| /* recover our scanner state: */ |
| scanner = &_tmesh_input->tmesh_scanner; |
| stack = _tmesh_input->tmesh_io_stack; |
| source = &stack->tmesh_io_stack_io; |
| |
| /* bump the input line: */ |
| source->tmesh_io_input_line += scanner->tmesh_scanner_next_line; |
| scanner->tmesh_scanner_next_line = 0; |
| |
| /* if we previously scanned the next token to return, return it |
| and clear it, unless it's EOF, which sticks: */ |
| token = scanner->tmesh_scanner_token_next; |
| if (token != TMESH_TOKEN_UNDEF) { |
| if (token != TMESH_TOKEN_EOF) { |
| scanner->tmesh_scanner_token_next = TMESH_TOKEN_UNDEF; |
| } |
| return (token); |
| } |
| |
| /* loop forever: */ |
| for (;;) { |
| |
| /* get the next character: */ |
| c = scanner->tmesh_scanner_c_next; |
| if (c == TMESH_C_UNDEF) { |
| c = (*source->tmesh_io_getc)(source); |
| } |
| scanner->tmesh_scanner_c_next = TMESH_C_UNDEF; |
| |
| /* if this is an EOF: */ |
| if (c == TMESH_C_EOF) { |
| |
| /* turn c into the EOF semicolon: */ |
| c = TMESH_C_EOF_SEMICOLON; |
| |
| /* if we have collected a token, save the EOF semicolon and return the token: */ |
| token = _tmesh_scanner_token(scanner); |
| if (token != TMESH_TOKEN_UNDEF) { |
| scanner->tmesh_scanner_c_next = c; |
| return (token); |
| } |
| } |
| |
| /* if this is an EOF semicolon: */ |
| if (c == TMESH_C_EOF_SEMICOLON) { |
| |
| /* quoted strings and comments (and commands, for that matter) cannot cross EOF boundaries: */ |
| scanner->tmesh_scanner_in_quotes = FALSE; |
| scanner->tmesh_scanner_in_comment = FALSE; |
| |
| /* close the now-finished source: */ |
| (*source->tmesh_io_close)(source, |
| (stack->tmesh_io_stack_next != NULL |
| ? &stack->tmesh_io_stack_next->tmesh_io_stack_io |
| : NULL)); |
| |
| /* pop the io stack: */ |
| _tmesh_input->tmesh_io_stack = stack->tmesh_io_stack_next; |
| tme_free(source->tmesh_io_name); |
| tme_free(stack); |
| |
| /* if we have emptied the source stack, we are really at EOF, |
| and the next time we're called we will return that: */ |
| stack = _tmesh_input->tmesh_io_stack; |
| source = &stack->tmesh_io_stack_io; |
| if (stack == NULL) { |
| scanner->tmesh_scanner_token_next = TMESH_TOKEN_EOF; |
| return (TMESH_TOKEN_EOF); |
| } |
| |
| /* return the EOF semicolon: */ |
| return (';'); |
| } |
| |
| /* if this is a yield: */ |
| if (c == TMESH_C_YIELD) { |
| |
| /* we are yielding: */ |
| _tmesh_input_yielding = TRUE; |
| |
| /* return an EOF token: */ |
| return (TMESH_TOKEN_EOF); |
| } |
| |
| /* if we're in a comment: */ |
| if (scanner->tmesh_scanner_in_comment) { |
| if (c != '\n') { |
| continue; |
| } |
| scanner->tmesh_scanner_in_comment = FALSE; |
| } |
| |
| /* if this is quotation marks: */ |
| if (c == '"') { |
| scanner->tmesh_scanner_in_quotes = !scanner->tmesh_scanner_in_quotes; |
| continue; |
| } |
| |
| /* other than quotation marks, every character either delimits |
| tokens or is collected into the current token: */ |
| if ( |
| |
| /* any character inside quotes is collected: */ |
| scanner->tmesh_scanner_in_quotes |
| |
| /* any alphanumeric character is collected: */ |
| || isalnum(c) |
| |
| /* any period, slash, hyphen, and underscore character is collected: */ |
| || c == '.' |
| || c == '/' |
| || c == '-' |
| || c == '_' |
| ) { |
| |
| /* allocate or grow the token buffer as needed. we always |
| make sure there's room for this new character, and a trailing |
| NUL that _tmesh_scanner_token may add: */ |
| if (scanner->tmesh_scanner_token_string_size == 0) { |
| scanner->tmesh_scanner_token_string_len = 0; |
| scanner->tmesh_scanner_token_string_size = 8; |
| scanner->tmesh_scanner_token_string = |
| _tmesh_gc_new(_tmesh_input, |
| char, |
| scanner->tmesh_scanner_token_string_size); |
| } |
| else if ((scanner->tmesh_scanner_token_string_len + 1) |
| >= scanner->tmesh_scanner_token_string_size) { |
| scanner->tmesh_scanner_token_string_size += |
| (2 |
| + (scanner->tmesh_scanner_token_string_size >> 1)); |
| scanner->tmesh_scanner_token_string = |
| _tmesh_gc_renew(_tmesh_input, |
| char, |
| scanner->tmesh_scanner_token_string, |
| scanner->tmesh_scanner_token_string_size); |
| } |
| |
| /* collect the character into the buffer: */ |
| scanner->tmesh_scanner_token_string[scanner->tmesh_scanner_token_string_len++] = c; |
| } |
| |
| /* delimit this token: */ |
| else { |
| |
| /* if we have collected a token, save the delimiter and return the token: */ |
| token = _tmesh_scanner_token(scanner); |
| if (token != TMESH_TOKEN_UNDEF) { |
| scanner->tmesh_scanner_c_next = c; |
| return (token); |
| } |
| |
| /* a carriage return or a newline becomes a semicolon, and |
| a pound sign begins a comment: */ |
| if (c == '\n') { |
| c = ';'; |
| scanner->tmesh_scanner_next_line = 1; |
| } |
| else if (c == '\r') { |
| c = ';'; |
| } |
| else if (c == '#') { |
| scanner->tmesh_scanner_in_comment = TRUE; |
| scanner->tmesh_scanner_in_args = FALSE; |
| continue; |
| } |
| |
| /* return a non-whitespace delimiter as a token, and this resets |
| the args state: */ |
| if (!isspace(c)) { |
| scanner->tmesh_scanner_in_args = FALSE; |
| return (c); |
| } |
| } |
| } |
| /* NOTREACHED */ |
| } |
| |
| /* this is called to parse input: */ |
| int |
| _tmesh_yyparse(struct tmesh *tmesh, struct tmesh_parser_value *value, char **_output, int *_yield) |
| { |
| struct tmesh_scanner *scanner; |
| int rc; |
| int command; |
| |
| /* initialize the scanner: */ |
| scanner = &tmesh->tmesh_scanner; |
| scanner->tmesh_scanner_token_next = TMESH_TOKEN_UNDEF; |
| scanner->tmesh_scanner_c_next = TMESH_C_UNDEF; |
| scanner->tmesh_scanner_in_comment = FALSE; |
| scanner->tmesh_scanner_in_quotes = FALSE; |
| scanner->tmesh_scanner_in_args = FALSE; |
| scanner->tmesh_scanner_token_string_size = 0; |
| |
| /* lock the input mutex: */ |
| tme_mutex_lock(&_tmesh_input_mutex); |
| |
| /* set this tmesh for input: */ |
| _tmesh_input = tmesh; |
| _tmesh_output = _output; |
| |
| /* assume that we will not have to yield: */ |
| _tmesh_input_yielding = FALSE; |
| |
| /* call the parser: */ |
| _tmesh_input_parsed = value; |
| rc = (yyparse() |
| ? EINVAL |
| : TME_OK); |
| |
| /* tell our caller if we're yielding: */ |
| *_yield = _tmesh_input_yielding; |
| |
| /* unlock the input mutex: */ |
| tme_mutex_unlock(&_tmesh_input_mutex); |
| |
| /* if the parse was successful, map the command token number to a command number: */ |
| if (rc == TME_OK && !*_yield) { |
| switch (value->tmesh_parser_value_token) { |
| default: assert(FALSE); |
| case TMESH_TOKEN_UNDEF: command = TMESH_COMMAND_NOP; break; |
| case TMESH_TOKEN_SOURCE: command = TMESH_COMMAND_SOURCE; break; |
| case TMESH_TOKEN_MKDIR: command = TMESH_COMMAND_MKDIR; break; |
| case TMESH_TOKEN_RMDIR: command = TMESH_COMMAND_RMDIR; break; |
| case TMESH_TOKEN_CD: command = TMESH_COMMAND_CD; break; |
| case TMESH_TOKEN_PWD: command = TMESH_COMMAND_PWD; break; |
| case TMESH_TOKEN_LS: command = TMESH_COMMAND_LS; break; |
| case TMESH_TOKEN_CONNECT: command = TMESH_COMMAND_CONNECT; break; |
| case TMESH_TOKEN_RM: command = TMESH_COMMAND_RM; break; |
| case TMESH_TOKEN_COMMAND: command = TMESH_COMMAND_COMMAND; break; |
| case TMESH_TOKEN_LOG: command = TMESH_COMMAND_LOG; break; |
| case TMESH_TOKEN_ALIAS: command = TMESH_COMMAND_ALIAS; break; |
| } |
| value->tmesh_parser_value_command = command; |
| } |
| |
| /* done: */ |
| return (rc); |
| } |
| #line 706 "tmesh-input.c" |
| /* allocate initial stack or double stack size, up to YYMAXDEPTH */ |
| static int yygrowstack(void); |
| static int yygrowstack(void) |
| { |
| int newsize, i; |
| short *newss; |
| YYSTYPE *newvs; |
| |
| if ((newsize = yystacksize) == 0) |
| newsize = YYINITSTACKSIZE; |
| else if (newsize >= YYMAXDEPTH) |
| return -1; |
| else if ((newsize *= 2) > YYMAXDEPTH) |
| newsize = YYMAXDEPTH; |
| i = yyssp - yyss; |
| if ((newss = (short *)realloc(yyss, newsize * sizeof *newss)) == NULL) |
| return -1; |
| yyss = newss; |
| yyssp = newss + i; |
| if ((newvs = (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs)) == NULL) |
| return -1; |
| yyvs = newvs; |
| yyvsp = newvs + i; |
| yystacksize = newsize; |
| yysslim = yyss + newsize - 1; |
| return 0; |
| } |
| |
| #define YYABORT goto yyabort |
| #define YYREJECT goto yyabort |
| #define YYACCEPT goto yyaccept |
| #define YYERROR goto yyerrlab |
| int |
| yyparse(void) |
| { |
| int yym, yyn, yystate; |
| #if YYDEBUG |
| const char *yys; |
| |
| if ((yys = getenv("YYDEBUG")) != NULL) |
| { |
| yyn = *yys; |
| if (yyn >= '0' && yyn <= '9') |
| yydebug = yyn - '0'; |
| } |
| #endif |
| |
| yynerrs = 0; |
| yyerrflag = 0; |
| yychar = (-1); |
| |
| if (yyss == NULL && yygrowstack()) goto yyoverflow; |
| yyssp = yyss; |
| yyvsp = yyvs; |
| *yyssp = yystate = 0; |
| |
| yyloop: |
| if ((yyn = yydefred[yystate]) != 0) goto yyreduce; |
| if (yychar < 0) |
| { |
| if ((yychar = yylex()) < 0) yychar = 0; |
| #if YYDEBUG |
| if (yydebug) |
| { |
| yys = 0; |
| if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; |
| if (!yys) yys = "illegal-symbol"; |
| printf("%sdebug: state %d, reading %d (%s)\n", |
| YYPREFIX, yystate, yychar, yys); |
| } |
| #endif |
| } |
| if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && |
| yyn <= YYTABLESIZE && yycheck[yyn] == yychar) |
| { |
| #if YYDEBUG |
| if (yydebug) |
| printf("%sdebug: state %d, shifting to state %d\n", |
| YYPREFIX, yystate, yytable[yyn]); |
| #endif |
| if (yyssp >= yysslim && yygrowstack()) |
| { |
| goto yyoverflow; |
| } |
| *++yyssp = yystate = yytable[yyn]; |
| *++yyvsp = yylval; |
| yychar = (-1); |
| if (yyerrflag > 0) --yyerrflag; |
| goto yyloop; |
| } |
| if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && |
| yyn <= YYTABLESIZE && yycheck[yyn] == yychar) |
| { |
| yyn = yytable[yyn]; |
| goto yyreduce; |
| } |
| if (yyerrflag) goto yyinrecovery; |
| goto yynewerror; |
| yynewerror: |
| yyerror("syntax error"); |
| goto yyerrlab; |
| yyerrlab: |
| ++yynerrs; |
| yyinrecovery: |
| if (yyerrflag < 3) |
| { |
| yyerrflag = 3; |
| for (;;) |
| { |
| if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && |
| yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) |
| { |
| #if YYDEBUG |
| if (yydebug) |
| printf("%sdebug: state %d, error recovery shifting\ |
| to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); |
| #endif |
| if (yyssp >= yysslim && yygrowstack()) |
| { |
| goto yyoverflow; |
| } |
| *++yyssp = yystate = yytable[yyn]; |
| *++yyvsp = yylval; |
| goto yyloop; |
| } |
| else |
| { |
| #if YYDEBUG |
| if (yydebug) |
| printf("%sdebug: error recovery discarding state %d\n", |
| YYPREFIX, *yyssp); |
| #endif |
| if (yyssp <= yyss) goto yyabort; |
| --yyssp; |
| --yyvsp; |
| } |
| } |
| } |
| else |
| { |
| if (yychar == 0) goto yyabort; |
| #if YYDEBUG |
| if (yydebug) |
| { |
| yys = 0; |
| if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; |
| if (!yys) yys = "illegal-symbol"; |
| printf("%sdebug: state %d, error recovery discards token %d (%s)\n", |
| YYPREFIX, yystate, yychar, yys); |
| } |
| #endif |
| yychar = (-1); |
| goto yyloop; |
| } |
| yyreduce: |
| #if YYDEBUG |
| if (yydebug) |
| printf("%sdebug: state %d, reducing by rule %d (%s)\n", |
| YYPREFIX, yystate, yyn, yyrule[yyn]); |
| #endif |
| yym = yylen[yyn]; |
| yyval = yyvsp[1-yym]; |
| switch (yyn) |
| { |
| case 1: |
| #line 99 "tmesh-input.y" |
| { *_tmesh_input_parsed = yyvsp[0]; YYACCEPT; } |
| break; |
| case 2: |
| #line 100 "tmesh-input.y" |
| { *_tmesh_input_parsed = yyvsp[0]; YYACCEPT; } |
| break; |
| case 3: |
| #line 101 "tmesh-input.y" |
| { *_tmesh_input_parsed = yyvsp[0]; YYACCEPT; } |
| break; |
| case 4: |
| #line 102 "tmesh-input.y" |
| { *_tmesh_input_parsed = yyvsp[0]; YYACCEPT; } |
| break; |
| case 5: |
| #line 103 "tmesh-input.y" |
| { *_tmesh_input_parsed = yyvsp[0]; YYACCEPT; } |
| break; |
| case 6: |
| #line 104 "tmesh-input.y" |
| { *_tmesh_input_parsed = yyvsp[0]; YYACCEPT; } |
| break; |
| case 7: |
| #line 105 "tmesh-input.y" |
| { *_tmesh_input_parsed = yyvsp[0]; YYACCEPT; } |
| break; |
| case 8: |
| #line 106 "tmesh-input.y" |
| { *_tmesh_input_parsed = yyvsp[0]; YYACCEPT; } |
| break; |
| case 9: |
| #line 107 "tmesh-input.y" |
| { *_tmesh_input_parsed = yyvsp[0]; YYACCEPT; } |
| break; |
| case 10: |
| #line 108 "tmesh-input.y" |
| { *_tmesh_input_parsed = yyvsp[0]; YYACCEPT; } |
| break; |
| case 11: |
| #line 109 "tmesh-input.y" |
| { *_tmesh_input_parsed = yyvsp[0]; YYACCEPT; } |
| break; |
| case 12: |
| #line 110 "tmesh-input.y" |
| { *_tmesh_input_parsed = yyvsp[0]; YYACCEPT; } |
| break; |
| case 13: |
| #line 111 "tmesh-input.y" |
| { YYABORT; } |
| break; |
| case 14: |
| #line 113 "tmesh-input.y" |
| { _tmesh_input_parsed->tmesh_parser_value_token = TMESH_TOKEN_UNDEF; YYACCEPT; } |
| break; |
| case 15: |
| #line 118 "tmesh-input.y" |
| { yyval = yyvsp[-1]; yyval.tmesh_parser_value_token = yyvsp[-2].tmesh_parser_value_token; } |
| break; |
| case 16: |
| #line 122 "tmesh-input.y" |
| { yyval = yyvsp[-1]; yyval.tmesh_parser_value_token = yyvsp[-2].tmesh_parser_value_token; } |
| break; |
| case 17: |
| #line 127 "tmesh-input.y" |
| { yyval = yyvsp[-1]; yyval.tmesh_parser_value_token = yyvsp[-2].tmesh_parser_value_token; } |
| break; |
| case 18: |
| #line 132 "tmesh-input.y" |
| { yyval = yyvsp[-1]; yyval.tmesh_parser_value_token = yyvsp[-2].tmesh_parser_value_token; } |
| break; |
| case 20: |
| #line 140 "tmesh-input.y" |
| { |
| yyval = yyvsp[-2]; |
| yyval.tmesh_parser_value_strings[1] = yyvsp[-1].tmesh_parser_value_strings[0]; |
| yyval.tmesh_parser_value_token = yyvsp[-3].tmesh_parser_value_token; |
| } |
| break; |
| case 21: |
| #line 149 "tmesh-input.y" |
| { yyval = yyvsp[-1]; yyval.tmesh_parser_value_token = yyvsp[-2].tmesh_parser_value_token; } |
| break; |
| case 22: |
| #line 151 "tmesh-input.y" |
| { yyval = yyvsp[-1]; yyval.tmesh_parser_value_token = TMESH_TOKEN_CONNECT; } |
| break; |
| case 23: |
| #line 156 "tmesh-input.y" |
| { yyval = yyvsp[-1]; yyval.tmesh_parser_value_token = yyvsp[-2].tmesh_parser_value_token; } |
| break; |
| case 24: |
| #line 161 "tmesh-input.y" |
| { |
| yyval = yyvsp[-2]; |
| yyval.tmesh_parser_value_strings[1] = yyvsp[-1].tmesh_parser_value_strings[0]; |
| yyval.tmesh_parser_value_token = yyvsp[-3].tmesh_parser_value_token; |
| } |
| break; |
| case 25: |
| #line 170 "tmesh-input.y" |
| { yyval = yyvsp[-1]; yyval.tmesh_parser_value_token = yyvsp[-2].tmesh_parser_value_token; } |
| break; |
| case 26: |
| #line 175 "tmesh-input.y" |
| { yyval = yyvsp[-1]; yyval.tmesh_parser_value_token = yyvsp[-2].tmesh_parser_value_token; } |
| break; |
| case 27: |
| #line 180 "tmesh-input.y" |
| { |
| yyval = yyvsp[-2]; |
| yyval.tmesh_parser_value_strings[1] = yyvsp[-1].tmesh_parser_value_strings[0]; |
| yyval.tmesh_parser_value_token = yyvsp[-3].tmesh_parser_value_token; |
| } |
| break; |
| case 30: |
| #line 194 "tmesh-input.y" |
| { yyval.tmesh_parser_value_strings[0] = NULL; } |
| break; |
| case 31: |
| #line 199 "tmesh-input.y" |
| { |
| _tmesh_parser_argv_arg(&yyval.tmesh_parser_value_argvs[0], |
| yyvsp[0].tmesh_parser_value_pathname0, |
| TRUE); |
| _tmesh_scanner_in_args(); |
| } |
| break; |
| case 32: |
| #line 206 "tmesh-input.y" |
| { |
| yyval = yyvsp[-1]; |
| _tmesh_parser_argv_arg(&yyval.tmesh_parser_value_argvs[0], |
| yyvsp[0].tmesh_parser_value_arg, |
| FALSE); |
| } |
| break; |
| case 33: |
| #line 216 "tmesh-input.y" |
| { |
| _tmesh_parser_argv_arg(&yyval.tmesh_parser_value_argvs[0], |
| yyvsp[0].tmesh_parser_value_arg, |
| TRUE); |
| } |
| break; |
| case 34: |
| #line 222 "tmesh-input.y" |
| { |
| yyval = yyvsp[-1]; |
| _tmesh_parser_argv_arg(&yyval.tmesh_parser_value_argvs[0], |
| yyvsp[0].tmesh_parser_value_arg, |
| FALSE); |
| } |
| break; |
| case 35: |
| #line 230 "tmesh-input.y" |
| { _tmesh_scanner_in_args(); } |
| break; |
| case 36: |
| #line 233 "tmesh-input.y" |
| { _tmesh_scanner_in_args(); } |
| break; |
| case 37: |
| #line 237 "tmesh-input.y" |
| { |
| if (yyvsp[-2].tmesh_parser_value_argvs[0].tmesh_parser_argv_argc > 1) { |
| yyerror(_("expected 'at'")); |
| YYERROR; |
| } |
| yyval.tmesh_parser_value_argvs[0] = yyvsp[-2].tmesh_parser_value_argvs[0]; |
| yyval.tmesh_parser_value_argvs[1].tmesh_parser_argv_argv = NULL; |
| yyval.tmesh_parser_value_argvs[2] = yyvsp[0].tmesh_parser_value_argvs[0]; |
| } |
| break; |
| case 38: |
| #line 247 "tmesh-input.y" |
| { |
| yyval.tmesh_parser_value_argvs[0] = yyvsp[-4].tmesh_parser_value_argvs[0]; |
| yyval.tmesh_parser_value_argvs[1] = yyvsp[-2].tmesh_parser_value_argvs[0]; |
| yyval.tmesh_parser_value_argvs[2] = yyvsp[0].tmesh_parser_value_argvs[0]; |
| } |
| break; |
| case 39: |
| #line 253 "tmesh-input.y" |
| { |
| yyval.tmesh_parser_value_argvs[0] = yyvsp[-2].tmesh_parser_value_argvs[0]; |
| yyval.tmesh_parser_value_argvs[1] = yyvsp[0].tmesh_parser_value_argvs[0]; |
| yyval.tmesh_parser_value_argvs[2].tmesh_parser_argv_argv = NULL; |
| } |
| break; |
| case 41: |
| #line 263 "tmesh-input.y" |
| { yyval.tmesh_parser_value_strings[0] = NULL; } |
| break; |
| #line 1066 "tmesh-input.c" |
| } |
| yyssp -= yym; |
| yystate = *yyssp; |
| yyvsp -= yym; |
| yym = yylhs[yyn]; |
| if (yystate == 0 && yym == 0) |
| { |
| #if YYDEBUG |
| if (yydebug) |
| printf("%sdebug: after reduction, shifting from state 0 to\ |
| state %d\n", YYPREFIX, YYFINAL); |
| #endif |
| yystate = YYFINAL; |
| *++yyssp = YYFINAL; |
| *++yyvsp = yyval; |
| if (yychar < 0) |
| { |
| if ((yychar = yylex()) < 0) yychar = 0; |
| #if YYDEBUG |
| if (yydebug) |
| { |
| yys = 0; |
| if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; |
| if (!yys) yys = "illegal-symbol"; |
| printf("%sdebug: state %d, reading %d (%s)\n", |
| YYPREFIX, YYFINAL, yychar, yys); |
| } |
| #endif |
| } |
| if (yychar == 0) goto yyaccept; |
| goto yyloop; |
| } |
| if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && |
| yyn <= YYTABLESIZE && yycheck[yyn] == yystate) |
| yystate = yytable[yyn]; |
| else |
| yystate = yydgoto[yym]; |
| #if YYDEBUG |
| if (yydebug) |
| printf("%sdebug: after reduction, shifting from state %d \ |
| to state %d\n", YYPREFIX, *yyssp, yystate); |
| #endif |
| if (yyssp >= yysslim && yygrowstack()) |
| { |
| goto yyoverflow; |
| } |
| *++yyssp = yystate; |
| *++yyvsp = yyval; |
| goto yyloop; |
| yyoverflow: |
| yyerror("yacc stack overflow"); |
| yyabort: |
| return (1); |
| yyaccept: |
| return (0); |
| } |