2 * Copyright 2011 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "parser.tab.h"
27 #include "wine/debug.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(vbscript
);
42 {L
"default", tDEFAULT
},
53 {L
"explicit", tEXPLICIT
},
56 {L
"function", tFUNCTION
},
70 {L
"nothing", tNOTHING
},
75 {L
"preserve", tPRESERVE
},
76 {L
"private", tPRIVATE
},
77 {L
"property", tPROPERTY
},
97 static inline BOOL
is_identifier_char(WCHAR c
)
99 return iswalnum(c
) || c
== '_';
102 static int check_keyword(parser_ctx_t
*ctx
, const WCHAR
*word
, const WCHAR
**lval
)
104 const WCHAR
*p1
= ctx
->ptr
;
105 const WCHAR
*p2
= word
;
108 while(p1
< ctx
->end
&& *p2
) {
116 if(*p2
|| (p1
< ctx
->end
&& is_identifier_char(*p1
)))
124 static int check_keywords(parser_ctx_t
*ctx
, const WCHAR
**lval
)
126 int min
= 0, max
= ARRAY_SIZE(keywords
)-1, r
, i
;
131 r
= check_keyword(ctx
, keywords
[i
].word
, lval
);
133 return keywords
[i
].token
;
144 static int parse_identifier(parser_ctx_t
*ctx
, const WCHAR
**ret
)
146 const WCHAR
*ptr
= ctx
->ptr
++;
150 while(ctx
->ptr
< ctx
->end
&& is_identifier_char(*ctx
->ptr
))
154 str
= parser_alloc(ctx
, (len
+1)*sizeof(WCHAR
));
158 memcpy(str
, ptr
, (len
+1)*sizeof(WCHAR
));
164 static int parse_string_literal(parser_ctx_t
*ctx
, const WCHAR
**ret
)
166 const WCHAR
*ptr
= ++ctx
->ptr
;
170 while(ctx
->ptr
< ctx
->end
) {
171 if(*ctx
->ptr
== '\n' || *ctx
->ptr
== '\r') {
172 FIXME("newline inside string literal\n");
176 if(*ctx
->ptr
== '"') {
177 if(ctx
->ptr
[1] != '"')
185 if(ctx
->ptr
== ctx
->end
) {
186 FIXME("unterminated string literal\n");
192 *ret
= rptr
= parser_alloc(ctx
, (len
+1)*sizeof(WCHAR
));
196 while(ptr
< ctx
->ptr
) {
207 static int parse_date_literal(parser_ctx_t
*ctx
, DATE
*ret
)
209 const WCHAR
*ptr
= ++ctx
->ptr
;
214 while(ctx
->ptr
< ctx
->end
) {
215 if(*ctx
->ptr
== '\n' || *ctx
->ptr
== '\r') {
216 FIXME("newline inside date literal\n");
225 if(ctx
->ptr
== ctx
->end
) {
226 FIXME("unterminated date literal\n");
232 rptr
= malloc((len
+1)*sizeof(WCHAR
));
236 memcpy( rptr
, ptr
, len
* sizeof(WCHAR
));
238 res
= VarDateFromStr(rptr
, ctx
->lcid
, 0, ret
);
241 FIXME("Invalid date literal\n");
249 static int parse_numeric_literal(parser_ctx_t
*ctx
, void **ret
)
256 if(*ctx
->ptr
== '0' && !('0' <= ctx
->ptr
[1] && ctx
->ptr
[1] <= '9') && ctx
->ptr
[1] != '.')
259 while(ctx
->ptr
< ctx
->end
&& is_digit(*ctx
->ptr
)) {
260 hlp
= d
*10 + *(ctx
->ptr
++) - '0';
261 if(d
>MAXLONGLONG
/10 || hlp
<0) {
268 while(ctx
->ptr
< ctx
->end
&& is_digit(*ctx
->ptr
)) {
273 if(*ctx
->ptr
== '.') {
277 while(ctx
->ptr
< ctx
->end
&& is_digit(*ctx
->ptr
)) {
278 hlp
= d
*10 + *(ctx
->ptr
++) - '0';
279 if(d
>MAXLONGLONG
/10 || hlp
<0)
285 while(ctx
->ptr
< ctx
->end
&& is_digit(*ctx
->ptr
))
289 if(*ctx
->ptr
== 'e' || *ctx
->ptr
== 'E') {
293 if(*ctx
->ptr
== '-') {
296 }else if(*ctx
->ptr
== '+') {
300 if(!is_digit(*ctx
->ptr
)) {
301 FIXME("Invalid numeric literal\n");
308 e
= e
*10 + *(ctx
->ptr
++) - '0';
309 if(sign
== -1 && -e
+exp
< -(INT_MAX
/100)) {
310 /* The literal will be rounded to 0 anyway. */
311 while(is_digit(*ctx
->ptr
))
317 if(sign
*e
+ exp
> INT_MAX
/100) {
318 FIXME("Invalid numeric literal\n");
321 } while(is_digit(*ctx
->ptr
));
326 if(use_int
&& (LONG
)d
== d
) {
331 r
= exp
>=0 ? d
*pow(10, exp
) : d
/pow(10, -exp
);
333 FIXME("Invalid numeric literal\n");
341 static int hex_to_int(WCHAR c
)
343 if('0' <= c
&& c
<= '9')
345 if('a' <= c
&& c
<= 'f')
347 if('A' <= c
&& c
<= 'F')
352 static int parse_hex_literal(parser_ctx_t
*ctx
, LONG
*ret
)
354 const WCHAR
*begin
= ctx
->ptr
;
357 while((d
= hex_to_int(*++ctx
->ptr
)) != -1)
360 if(begin
+ 9 /* max digits+1 */ < ctx
->ptr
) {
361 FIXME("invalid literal\n");
365 if(*ctx
->ptr
== '&') {
369 *ret
= l
== (UINT16
)l
? (INT16
)l
: l
;
374 static void skip_spaces(parser_ctx_t
*ctx
)
376 while(*ctx
->ptr
== ' ' || *ctx
->ptr
== '\t')
380 static int comment_line(parser_ctx_t
*ctx
)
382 ctx
->ptr
= wcspbrk(ctx
->ptr
, L
"\n\r");
390 static int parse_next_token(void *lval
, unsigned *loc
, parser_ctx_t
*ctx
)
395 *loc
= ctx
->ptr
- ctx
->code
;
396 if(ctx
->ptr
== ctx
->end
)
397 return ctx
->last_token
== tNL
? 0 : tNL
;
401 if('0' <= c
&& c
<= '9')
402 return parse_numeric_literal(ctx
, lval
);
406 if(ctx
->last_token
!= '.' && ctx
->last_token
!= tDOT
)
407 ret
= check_keywords(ctx
, lval
);
409 return parse_identifier(ctx
, lval
);
421 return comment_line(ctx
);
434 * We need to distinguish between '.' used as part of a member expression and
435 * a beginning of a dot expression (a member expression accessing with statement
436 * expression) and a floating point number like ".2" .
438 c
= ctx
->ptr
> ctx
->code
? ctx
->ptr
[-1] : '\n';
439 if (is_identifier_char(c
) || c
== ')') {
444 if('0' <= c
&& c
<= '9')
445 return parse_numeric_literal(ctx
, lval
);
449 if(ctx
->is_html
&& ctx
->ptr
[1] == '-' && ctx
->ptr
[2] == '>')
450 return comment_line(ctx
);
455 * We resolve empty brackets in lexer instead of parser to avoid complex conflicts
456 * in call statement special case |f()| without 'call' keyword
460 if(*ctx
->ptr
== ')') {
462 return tEMPTYBRACKETS
;
465 * Parser can't predict if bracket is part of argument expression or an argument
466 * in call expression. We predict it here instead.
468 if(ctx
->last_token
== tIdentifier
|| ctx
->last_token
== ')')
470 return tEXPRLBRACKET
;
472 return parse_string_literal(ctx
, lval
);
474 return parse_date_literal(ctx
, lval
);
476 if((*++ctx
->ptr
== 'h' || *ctx
->ptr
== 'H') && hex_to_int(ctx
->ptr
[1]) != -1)
477 return parse_hex_literal(ctx
, lval
);
480 switch(*++ctx
->ptr
) {
490 switch(*++ctx
->ptr
) {
498 if(ctx
->is_html
&& ctx
->ptr
[1] == '-' && ctx
->ptr
[2] == '-')
499 return comment_line(ctx
);
503 switch(*++ctx
->ptr
) {
513 FIXME("Unhandled char %c in %s\n", *ctx
->ptr
, debugstr_w(ctx
->ptr
));
519 int parser_lex(void *lval
, unsigned *loc
, parser_ctx_t
*ctx
)
523 if (ctx
->last_token
== tEXPRESSION
)
525 ctx
->last_token
= tNL
;
530 ret
= parse_next_token(lval
, loc
, ctx
);
533 if(*ctx
->ptr
!= '\n' && *ctx
->ptr
!= '\r') {
534 FIXME("'_' not followed by newline\n");
537 if(*ctx
->ptr
== '\r')
539 if(*ctx
->ptr
== '\n')
543 if(ret
!= tNL
|| ctx
->last_token
!= tNL
)
546 ctx
->last_nl
= ctx
->ptr
-ctx
->code
;
549 return (ctx
->last_token
= ret
);