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 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