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