xref: /PHP-7.4/sapi/phpdbg/phpdbg_parser.y (revision 25103c37)
1 %{
2 
3 /*
4  * phpdbg_parser.y
5  * (from php-src root)
6  */
7 
8 #include "phpdbg.h"
9 #include "phpdbg_cmd.h"
10 #include "phpdbg_utils.h"
11 #include "phpdbg_cmd.h"
12 #include "phpdbg_prompt.h"
13 
14 #define YYSTYPE phpdbg_param_t
15 
16 #include "phpdbg_parser.h"
17 #include "phpdbg_lexer.h"
18 
19 #undef yyerror
20 static int yyerror(const char *msg);
21 
22 ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
23 
24 #ifdef _MSC_VER
25 #define YYMALLOC malloc
26 #define YYFREE free
27 #endif
28 
29 %}
30 
31 %define api.pure full
32 %define parse.error verbose
33 
34 %code requires {
35 #include "phpdbg.h"
36 #ifndef YY_TYPEDEF_YY_SCANNER_T
37 #define YY_TYPEDEF_YY_SCANNER_T
38 typedef void* yyscan_t;
39 #endif
40 }
41 
42 %token T_EVAL       "eval"
43 %token T_RUN        "run"
44 %token T_SHELL      "shell"
45 %token T_IF         "if (condition)"
46 %token T_TRUTHY     "truthy (true, on, yes or enabled)"
47 %token T_FALSY      "falsy (false, off, no or disabled)"
48 %token T_STRING     "string (some input, perhaps)"
49 %token T_COLON      ": (colon)"
50 %token T_DCOLON     ":: (double colon)"
51 %token T_POUND      "# (pound sign followed by digits)"
52 %token T_SEPARATOR  "# (pound sign)"
53 %token T_PROTO      "protocol (file://)"
54 %token T_DIGITS     "digits (numbers)"
55 %token T_LITERAL    "literal (string)"
56 %token T_ADDR       "address"
57 %token T_OPCODE     "opcode"
58 %token T_ID         "identifier (command or function name)"
59 %token T_INPUT      "input (input string or data)"
60 %token T_UNEXPECTED "input"
61 %token T_REQ_ID     "request id (-r %d)"
62 
63 %% /* Rules */
64 
65 input
66 	: command { $$ = $1; }
67 	| input T_SEPARATOR command { phpdbg_stack_separate($1.top); $$ = $3; }
68 	| /* empty */
69 	;
70 
71 command
72 	: parameters { $$.top = PHPDBG_G(parser_stack)->top; }
73 	| full_expression { phpdbg_stack_push(PHPDBG_G(parser_stack), &$1); $$.top = PHPDBG_G(parser_stack)->top; }
74 	;
75 
76 parameters
77 	: parameter { phpdbg_stack_push(PHPDBG_G(parser_stack), &$1); $$.top = PHPDBG_G(parser_stack)->top; }
78 	| parameters parameter { phpdbg_stack_push(PHPDBG_G(parser_stack), &$2); $$.top = PHPDBG_G(parser_stack)->top; }
79 	| parameters T_REQ_ID { $$ = $1; PHPDBG_G(req_id) = $2.num; }
80 	;
81 
82 parameter
83 	: T_ID T_COLON T_DIGITS {
84 		$$.type = FILE_PARAM;
85 		$$.file.name = $2.str;
86 		$$.file.line = $3.num;
87 	}
88 	| T_ID T_COLON T_POUND T_DIGITS {
89 		$$.type = NUMERIC_FILE_PARAM;
90 		$$.file.name = $1.str;
91 		$$.file.line = $4.num;
92 	}
93 	| T_PROTO T_ID T_COLON T_DIGITS {
94 		$$.type = FILE_PARAM;
95 		$$.file.name = malloc($1.len + $2.len + 1);
96 		if ($$.file.name) {
97 			memcpy(&$$.file.name[0], $1.str, $1.len);
98 			memcpy(&$$.file.name[$1.len], $2.str, $2.len);
99 			$$.file.name[$1.len + $2.len] = '\0';
100 		}
101 		$$.file.line = $4.num;
102 	}
103 	| T_PROTO T_ID T_COLON T_POUND T_DIGITS {
104 		$$.type = NUMERIC_FILE_PARAM;
105 		$$.file.name = malloc($1.len + $2.len + 1);
106 		if ($$.file.name) {
107 			memcpy(&$$.file.name[0], $1.str, $1.len);
108 			memcpy(&$$.file.name[$1.len], $2.str, $2.len);
109 			$$.file.name[$1.len + $2.len] = '\0';
110 		}
111 		$$.file.line = $5.num;
112 	}
113 	| T_ID T_DCOLON T_ID {
114 		$$.type = METHOD_PARAM;
115 		$$.method.class = $1.str;
116 		$$.method.name = $3.str;
117 	}
118 	| T_ID T_DCOLON T_ID T_POUND T_DIGITS {
119 		$$.type = NUMERIC_METHOD_PARAM;
120 		$$.method.class = $1.str;
121 		$$.method.name = $3.str;
122 		$$.num = $5.num;
123 	}
124 	| T_ID T_POUND T_DIGITS {
125 		$$.type = NUMERIC_FUNCTION_PARAM;
126 		$$.str = $1.str;
127 		$$.len = $1.len;
128 		$$.num = $3.num;
129 	}
130 	| T_IF T_INPUT {
131 		$$.type = COND_PARAM;
132 		$$.str = $2.str;
133 		$$.len = $2.len;
134 	}
135 	| T_OPCODE { $$ = $1; }
136 	| T_ADDR { $$ = $1; }
137 	| T_LITERAL { $$ = $1; }
138 	| T_TRUTHY { $$ = $1; }
139 	| T_FALSY { $$ = $1; }
140 	| T_DIGITS { $$ = $1; }
141 	| T_ID { $$ = $1; }
142 	;
143 
144 req_id
145 	: T_REQ_ID { PHPDBG_G(req_id) = $1.num; }
146 	| /* empty */
147 ;
148 
149 full_expression
150 	: T_EVAL req_id T_INPUT {
151 		$$.type = EVAL_PARAM;
152 		$$.str = $3.str;
153 		$$.len = $3.len;
154 	}
155 	| T_SHELL req_id T_INPUT {
156 		$$.type = SHELL_PARAM;
157 		$$.str = $3.str;
158 		$$.len = $3.len;
159 	}
160 	| T_RUN req_id {
161 		$$.type = RUN_PARAM;
162 		$$.len = 0;
163 	}
164 	| T_RUN req_id T_INPUT {
165 		$$.type = RUN_PARAM;
166 		$$.str = $3.str;
167 		$$.len = $3.len;
168 	}
169 	;
170 
171 %%
172 
173 static int yyerror(const char *msg) {
174 	phpdbg_error("command", "type=\"parseerror\" msg=\"%s\"", "Parse Error: %s", msg);
175 
176 	{
177 		const phpdbg_param_t *top = PHPDBG_G(parser_stack);
178 
179 		while (top) {
180 			phpdbg_param_debug(top, "--> ");
181 			top = top->next;
182 		}
183 	}
184 	return 0;
185 }
186 
phpdbg_do_parse(phpdbg_param_t * stack,char * input)187 int phpdbg_do_parse(phpdbg_param_t *stack, char *input) {
188 	if (!*input) {
189 		return 0;
190 	}
191 
192 	if (PHPDBG_G(cur_command)) {
193 		free(PHPDBG_G(cur_command));
194 	}
195 	PHPDBG_G(cur_command) = strdup(input);
196 
197 	phpdbg_init_lexer(stack, input);
198 
199 	return yyparse();
200 }
201