ReactOS  0.4.14-dev-593-g1793dcc
lex.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
3  *
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.
8  *
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.
13  *
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
17  */
18 
19 
20 #include <limits.h>
21 #include <math.h>
22 
23 #include "jscript.h"
24 #include "activscp.h"
25 #include "objsafe.h"
26 #include "engine.h"
27 #include "parser.h"
28 
29 #include "parser.tab.h"
30 
31 #include "wine/debug.h"
32 
34 
35 static const struct {
36  const WCHAR *word;
37  int token;
39  unsigned min_version;
40 } keywords[] = {
41  {L"break", kBREAK, TRUE},
42  {L"case", kCASE},
43  {L"catch", kCATCH},
44  {L"continue", kCONTINUE, TRUE},
45  {L"default", kDEFAULT},
46  {L"delete", kDELETE},
47  {L"do", kDO},
48  {L"else", kELSE},
49  {L"false", kFALSE},
50  {L"finally", kFINALLY},
51  {L"for", kFOR},
52  {L"function", kFUNCTION},
54  {L"if", kIF},
55  {L"in", kIN},
56  {L"instanceof", kINSTANCEOF},
57  {L"new", kNEW},
58  {L"null", kNULL},
59  {L"return", kRETURN, TRUE},
61  {L"switch", kSWITCH},
62  {L"this", kTHIS},
63  {L"throw", kTHROW},
64  {L"true", kTRUE},
65  {L"try", kTRY},
66  {L"typeof", kTYPEOF},
67  {L"var", kVAR},
68  {L"void", kVOID},
69  {L"while", kWHILE},
70  {L"with", kWITH}
71 };
72 
74 {
75  ctx->hres = hres;
76  ctx->lexer_error = TRUE;
77  return -1;
78 }
79 
80 /* ECMA-262 3rd Edition 7.6 */
82 {
83  return iswalnum(c) || c == '$' || c == '_' || c == '\\';
84 }
85 
87 {
88  return iswalpha(c) || c == '$' || c == '_' || c == '\\';
89 }
90 
91 static int check_keyword(parser_ctx_t *ctx, const WCHAR *word, const WCHAR **lval)
92 {
93  const WCHAR *p1 = ctx->ptr;
94  const WCHAR *p2 = word;
95 
96  while(p1 < ctx->end && *p2) {
97  if(*p1 != *p2)
98  return *p1 - *p2;
99  p1++;
100  p2++;
101  }
102 
103  if(*p2 || (p1 < ctx->end && is_identifier_char(*p1)))
104  return 1;
105 
106  if(lval)
107  *lval = word;
108  ctx->ptr = p1;
109  return 0;
110 }
111 
112 /* ECMA-262 3rd Edition 7.3 */
114 {
115  return c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029;
116 }
117 
118 static int hex_to_int(WCHAR c)
119 {
120  if('0' <= c && c <= '9')
121  return c-'0';
122 
123  if('a' <= c && c <= 'f')
124  return c-'a'+10;
125 
126  if('A' <= c && c <= 'F')
127  return c-'A'+10;
128 
129  return -1;
130 }
131 
132 static int check_keywords(parser_ctx_t *ctx, const WCHAR **lval)
133 {
134  int min = 0, max = ARRAY_SIZE(keywords)-1, r, i;
135 
136  while(min <= max) {
137  i = (min+max)/2;
138 
139  r = check_keyword(ctx, keywords[i].word, lval);
140  if(!r) {
141  if(ctx->script->version < keywords[i].min_version) {
142  TRACE("ignoring keyword %s in incompatible mode\n",
144  ctx->ptr -= lstrlenW(keywords[i].word);
145  return 0;
146  }
147  ctx->implicit_nl_semicolon = keywords[i].no_nl;
148  return keywords[i].token;
149  }
150 
151  if(r > 0)
152  min = i+1;
153  else
154  max = i-1;
155  }
156 
157  return 0;
158 }
159 
161 {
162  const WCHAR html_commentW[] = {'<','!','-','-',0};
163 
164  if(!ctx->is_html || ctx->ptr+3 >= ctx->end ||
165  memcmp(ctx->ptr, html_commentW, sizeof(WCHAR)*4))
166  return FALSE;
167 
168  ctx->nl = TRUE;
169  while(ctx->ptr < ctx->end && !is_endline(*ctx->ptr++));
170 
171  return TRUE;
172 }
173 
175 {
176  if(ctx->ptr+1 >= ctx->end)
177  return FALSE;
178 
179  if(*ctx->ptr != '/') {
180  if(*ctx->ptr == '@' && ctx->ptr+2 < ctx->end && ctx->ptr[1] == '*' && ctx->ptr[2] == '/') {
181  ctx->ptr += 3;
182  return TRUE;
183  }
184 
185  return FALSE;
186  }
187 
188  switch(ctx->ptr[1]) {
189  case '*':
190  ctx->ptr += 2;
191  if(ctx->ptr+2 < ctx->end && *ctx->ptr == '@' && is_identifier_char(ctx->ptr[1]))
192  return FALSE;
193  while(ctx->ptr+1 < ctx->end && (ctx->ptr[0] != '*' || ctx->ptr[1] != '/'))
194  ctx->ptr++;
195 
196  if(ctx->ptr[0] == '*' && ctx->ptr[1] == '/') {
197  ctx->ptr += 2;
198  }else {
199  WARN("unexpected end of file (missing end of comment)\n");
200  ctx->ptr = ctx->end;
201  }
202  break;
203  case '/':
204  ctx->ptr += 2;
205  if(ctx->ptr+2 < ctx->end && *ctx->ptr == '@' && is_identifier_char(ctx->ptr[1]))
206  return FALSE;
207  while(ctx->ptr < ctx->end && !is_endline(*ctx->ptr))
208  ctx->ptr++;
209  break;
210  default:
211  return FALSE;
212  }
213 
214  return TRUE;
215 }
216 
218 {
219  while(ctx->ptr < ctx->end && (iswspace(*ctx->ptr) || *ctx->ptr == 0xFEFF /* UTF16 BOM */)) {
220  if(is_endline(*ctx->ptr++))
221  ctx->nl = TRUE;
222  }
223 
224  return ctx->ptr != ctx->end;
225 }
226 
228 {
229  WCHAR *pd, *p, c, *end = str + *len;
230  int i;
231 
232  pd = p = str;
233  while(p < end) {
234  if(*p != '\\') {
235  *pd++ = *p++;
236  continue;
237  }
238 
239  if(++p == end)
240  return FALSE;
241 
242  switch(*p) {
243  case '\'':
244  case '\"':
245  case '\\':
246  c = *p;
247  break;
248  case 'b':
249  c = '\b';
250  break;
251  case 't':
252  c = '\t';
253  break;
254  case 'n':
255  c = '\n';
256  break;
257  case 'f':
258  c = '\f';
259  break;
260  case 'r':
261  c = '\r';
262  break;
263  case 'x':
264  if(p + 2 >= end)
265  return FALSE;
266  i = hex_to_int(*++p);
267  if(i == -1)
268  return FALSE;
269  c = i << 4;
270 
271  i = hex_to_int(*++p);
272  if(i == -1)
273  return FALSE;
274  c += i;
275  break;
276  case 'u':
277  if(p + 4 >= end)
278  return FALSE;
279  i = hex_to_int(*++p);
280  if(i == -1)
281  return FALSE;
282  c = i << 12;
283 
284  i = hex_to_int(*++p);
285  if(i == -1)
286  return FALSE;
287  c += i << 8;
288 
289  i = hex_to_int(*++p);
290  if(i == -1)
291  return FALSE;
292  c += i << 4;
293 
294  i = hex_to_int(*++p);
295  if(i == -1)
296  return FALSE;
297  c += i;
298  break;
299  default:
300  if(iswdigit(*p)) {
301  c = *p++ - '0';
302  if(p < end && iswdigit(*p)) {
303  c = c*8 + (*p++ - '0');
304  if(p < end && iswdigit(*p))
305  c = c*8 + (*p++ - '0');
306  }
307  p--;
308  }
309  else
310  c = *p;
311  }
312 
313  *pd++ = c;
314  p++;
315  }
316 
317  *len = pd - str;
318  return TRUE;
319 }
320 
321 static int parse_identifier(parser_ctx_t *ctx, const WCHAR **ret)
322 {
323  const WCHAR *ptr = ctx->ptr++;
324  WCHAR *wstr;
325  int len;
326 
327  while(ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr))
328  ctx->ptr++;
329 
330  len = ctx->ptr-ptr;
331 
332  *ret = wstr = parser_alloc(ctx, (len+1)*sizeof(WCHAR));
333  memcpy(wstr, ptr, len*sizeof(WCHAR));
334  wstr[len] = 0;
335 
336  /* FIXME: unescape */
337  return tIdentifier;
338 }
339 
341 {
342  const WCHAR *ptr = ++ctx->ptr, *ret_str = ptr;
343  BOOL needs_unescape = FALSE;
344  WCHAR *unescape_str;
345  size_t len;
346 
347  while(ctx->ptr < ctx->end && *ctx->ptr != endch) {
348  if(*ctx->ptr++ == '\\') {
349  ctx->ptr++;
350  needs_unescape = TRUE;
351  }
352  }
353 
354  if(ctx->ptr == ctx->end)
355  return lex_error(ctx, JS_E_UNTERMINATED_STRING);
356 
357  len = ctx->ptr - ptr;
358  ctx->ptr++;
359 
360  if(needs_unescape) {
361  ret_str = unescape_str = parser_alloc(ctx, len * sizeof(WCHAR));
362  if(!unescape_str)
363  return lex_error(ctx, E_OUTOFMEMORY);
364  memcpy(unescape_str, ptr, len * sizeof(WCHAR));
365  if(!unescape(unescape_str, &len)) {
366  WARN("unescape failed\n");
367  return lex_error(ctx, E_FAIL);
368  }
369  }
370 
371  if(!(*ret = compiler_alloc_string_len(ctx->compiler, ret_str, len)))
372  return lex_error(ctx, E_OUTOFMEMORY);
373 
374  /* FIXME: leaking string */
375  return tStringLiteral;
376 }
377 
379 {
380  literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
381 
382  ret->type = LT_DOUBLE;
383  ret->u.dval = d;
384  return ret;
385 }
386 
388 {
389  literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
390 
391  ret->type = LT_BOOL;
392  ret->u.bval = bval;
393 
394  return ret;
395 }
396 
397 HRESULT parse_decimal(const WCHAR **iter, const WCHAR *end, double *ret)
398 {
399  const WCHAR *ptr = *iter;
400  LONGLONG d = 0, hlp;
401  int exp = 0;
402 
403  while(ptr < end && iswdigit(*ptr)) {
404  hlp = d*10 + *(ptr++) - '0';
405  if(d>MAXLONGLONG/10 || hlp<0) {
406  exp++;
407  break;
408  }
409  else
410  d = hlp;
411  }
412  while(ptr < end && iswdigit(*ptr)) {
413  exp++;
414  ptr++;
415  }
416 
417  if(*ptr == '.') {
418  ptr++;
419 
420  while(ptr < end && iswdigit(*ptr)) {
421  hlp = d*10 + *(ptr++) - '0';
422  if(d>MAXLONGLONG/10 || hlp<0)
423  break;
424 
425  d = hlp;
426  exp--;
427  }
428  while(ptr < end && iswdigit(*ptr))
429  ptr++;
430  }
431 
432  if(ptr < end && (*ptr == 'e' || *ptr == 'E')) {
433  int sign = 1, e = 0;
434 
435  if(++ptr < end) {
436  if(*ptr == '+') {
437  ptr++;
438  }else if(*ptr == '-') {
439  sign = -1;
440  ptr++;
441  }else if(!iswdigit(*ptr)) {
442  WARN("Expected exponent part\n");
443  return E_FAIL;
444  }
445  }
446 
447  if(ptr == end) {
448  WARN("unexpected end of file\n");
449  return E_FAIL;
450  }
451 
452  while(ptr < end && iswdigit(*ptr)) {
453  if(e > INT_MAX/10 || (e = e*10 + *ptr++ - '0')<0)
454  e = INT_MAX;
455  }
456  e *= sign;
457 
458  if(exp<0 && e<0 && e+exp>0) exp = INT_MIN;
459  else if(exp>0 && e>0 && e+exp<0) exp = INT_MAX;
460  else exp += e;
461  }
462 
463  if(is_identifier_char(*ptr)) {
464  WARN("wrong char after zero\n");
465  return JS_E_MISSING_SEMICOLON;
466  }
467 
468  *ret = exp>=0 ? d*pow(10, exp) : d/pow(10, -exp);
469  *iter = ptr;
470  return S_OK;
471 }
472 
474 {
475  HRESULT hres;
476 
477  if(*ctx->ptr == '0') {
478  ctx->ptr++;
479 
480  if(*ctx->ptr == 'x' || *ctx->ptr == 'X') {
481  double r = 0;
482  int d;
483  if(++ctx->ptr == ctx->end) {
484  ERR("unexpected end of file\n");
485  return FALSE;
486  }
487 
488  while(ctx->ptr < ctx->end && (d = hex_to_int(*ctx->ptr)) != -1) {
489  r = r*16 + d;
490  ctx->ptr++;
491  }
492 
493  if(ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr)) {
494  WARN("unexpected identifier char\n");
496  return FALSE;
497  }
498 
499  *ret = r;
500  return TRUE;
501  }
502 
503  if(iswdigit(*ctx->ptr)) {
504  unsigned base = 8;
505  const WCHAR *ptr;
506  double val = 0;
507 
508  for(ptr = ctx->ptr; ptr < ctx->end && iswdigit(*ptr); ptr++) {
509  if(*ptr > '7') {
510  base = 10;
511  break;
512  }
513  }
514 
515  do {
516  val = val*base + *ctx->ptr-'0';
517  }while(++ctx->ptr < ctx->end && iswdigit(*ctx->ptr));
518 
519  /* FIXME: Do we need it here? */
520  if(ctx->ptr < ctx->end && (is_identifier_char(*ctx->ptr) || *ctx->ptr == '.')) {
521  WARN("wrong char after octal literal: '%c'\n", *ctx->ptr);
523  return FALSE;
524  }
525 
526  *ret = val;
527  return TRUE;
528  }
529 
530  if(is_identifier_char(*ctx->ptr)) {
531  WARN("wrong char after zero\n");
533  return FALSE;
534  }
535  }
536 
537  hres = parse_decimal(&ctx->ptr, ctx->end, ret);
538  if(FAILED(hres)) {
539  lex_error(ctx, hres);
540  return FALSE;
541  }
542 
543  return TRUE;
544 }
545 
546 static int next_token(parser_ctx_t *ctx, void *lval)
547 {
548  do {
549  if(!skip_spaces(ctx))
550  return tEOF;
551  }while(skip_comment(ctx) || skip_html_comment(ctx));
552 
553  if(ctx->implicit_nl_semicolon) {
554  if(ctx->nl)
555  return ';';
556  ctx->implicit_nl_semicolon = FALSE;
557  }
558 
559  if(iswalpha(*ctx->ptr)) {
560  int ret = check_keywords(ctx, lval);
561  if(ret)
562  return ret;
563 
564  return parse_identifier(ctx, lval);
565  }
566 
567  if(iswdigit(*ctx->ptr)) {
568  double n;
569 
570  if(!parse_numeric_literal(ctx, &n))
571  return -1;
572 
573  *(literal_t**)lval = new_double_literal(ctx, n);
574  return tNumericLiteral;
575  }
576 
577  switch(*ctx->ptr) {
578  case '{':
579  case '(':
580  case ')':
581  case '[':
582  case ']':
583  case ';':
584  case ',':
585  case '~':
586  case '?':
587  return *ctx->ptr++;
588 
589  case '}':
590  *(const WCHAR**)lval = ctx->ptr++;
591  return '}';
592 
593  case '.':
594  if(ctx->ptr+1 < ctx->end && iswdigit(ctx->ptr[1])) {
595  double n;
596  HRESULT hres;
597  hres = parse_decimal(&ctx->ptr, ctx->end, &n);
598  if(FAILED(hres)) {
599  lex_error(ctx, hres);
600  return -1;
601  }
602  *(literal_t**)lval = new_double_literal(ctx, n);
603  return tNumericLiteral;
604  }
605  ctx->ptr++;
606  return '.';
607 
608  case '<':
609  if(++ctx->ptr == ctx->end) {
610  *(int*)lval = EXPR_LESS;
611  return tRelOper;
612  }
613 
614  switch(*ctx->ptr) {
615  case '=': /* <= */
616  ctx->ptr++;
617  *(int*)lval = EXPR_LESSEQ;
618  return tRelOper;
619  case '<': /* << */
620  if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* <<= */
621  ctx->ptr++;
622  *(int*)lval = EXPR_ASSIGNLSHIFT;
623  return tAssignOper;
624  }
625  *(int*)lval = EXPR_LSHIFT;
626  return tShiftOper;
627  default: /* < */
628  *(int*)lval = EXPR_LESS;
629  return tRelOper;
630  }
631 
632  case '>':
633  if(++ctx->ptr == ctx->end) { /* > */
634  *(int*)lval = EXPR_GREATER;
635  return tRelOper;
636  }
637 
638  switch(*ctx->ptr) {
639  case '=': /* >= */
640  ctx->ptr++;
641  *(int*)lval = EXPR_GREATEREQ;
642  return tRelOper;
643  case '>': /* >> */
644  if(++ctx->ptr < ctx->end) {
645  if(*ctx->ptr == '=') { /* >>= */
646  ctx->ptr++;
647  *(int*)lval = EXPR_ASSIGNRSHIFT;
648  return tAssignOper;
649  }
650  if(*ctx->ptr == '>') { /* >>> */
651  if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* >>>= */
652  ctx->ptr++;
653  *(int*)lval = EXPR_ASSIGNRRSHIFT;
654  return tAssignOper;
655  }
656  *(int*)lval = EXPR_RRSHIFT;
657  return tRelOper;
658  }
659  }
660  *(int*)lval = EXPR_RSHIFT;
661  return tShiftOper;
662  default:
663  *(int*)lval = EXPR_GREATER;
664  return tRelOper;
665  }
666 
667  case '+':
668  ctx->ptr++;
669  if(ctx->ptr < ctx->end) {
670  switch(*ctx->ptr) {
671  case '+': /* ++ */
672  ctx->ptr++;
673  return tINC;
674  case '=': /* += */
675  ctx->ptr++;
676  *(int*)lval = EXPR_ASSIGNADD;
677  return tAssignOper;
678  }
679  }
680  return '+';
681 
682  case '-':
683  ctx->ptr++;
684  if(ctx->ptr < ctx->end) {
685  switch(*ctx->ptr) {
686  case '-': /* -- or --> */
687  ctx->ptr++;
688  if(ctx->is_html && ctx->nl && ctx->ptr < ctx->end && *ctx->ptr == '>') {
689  ctx->ptr++;
690  return tHTMLCOMMENT;
691  }
692  return tDEC;
693  case '=': /* -= */
694  ctx->ptr++;
695  *(int*)lval = EXPR_ASSIGNSUB;
696  return tAssignOper;
697  }
698  }
699  return '-';
700 
701  case '*':
702  if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* *= */
703  ctx->ptr++;
704  *(int*)lval = EXPR_ASSIGNMUL;
705  return tAssignOper;
706  }
707  return '*';
708 
709  case '%':
710  if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* %= */
711  ctx->ptr++;
712  *(int*)lval = EXPR_ASSIGNMOD;
713  return tAssignOper;
714  }
715  return '%';
716 
717  case '&':
718  if(++ctx->ptr < ctx->end) {
719  switch(*ctx->ptr) {
720  case '=': /* &= */
721  ctx->ptr++;
722  *(int*)lval = EXPR_ASSIGNAND;
723  return tAssignOper;
724  case '&': /* && */
725  ctx->ptr++;
726  return tANDAND;
727  }
728  }
729  return '&';
730 
731  case '|':
732  if(++ctx->ptr < ctx->end) {
733  switch(*ctx->ptr) {
734  case '=': /* |= */
735  ctx->ptr++;
736  *(int*)lval = EXPR_ASSIGNOR;
737  return tAssignOper;
738  case '|': /* || */
739  ctx->ptr++;
740  return tOROR;
741  }
742  }
743  return '|';
744 
745  case '^':
746  if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* ^= */
747  ctx->ptr++;
748  *(int*)lval = EXPR_ASSIGNXOR;
749  return tAssignOper;
750  }
751  return '^';
752 
753  case '!':
754  if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* != */
755  if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* !== */
756  ctx->ptr++;
757  *(int*)lval = EXPR_NOTEQEQ;
758  return tEqOper;
759  }
760  *(int*)lval = EXPR_NOTEQ;
761  return tEqOper;
762  }
763  return '!';
764 
765  case '=':
766  if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* == */
767  if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* === */
768  ctx->ptr++;
769  *(int*)lval = EXPR_EQEQ;
770  return tEqOper;
771  }
772  *(int*)lval = EXPR_EQ;
773  return tEqOper;
774  }
775  return '=';
776 
777  case '/':
778  if(++ctx->ptr < ctx->end) {
779  if(*ctx->ptr == '=') { /* /= */
780  ctx->ptr++;
781  *(int*)lval = EXPR_ASSIGNDIV;
782  return kDIVEQ;
783  }
784  }
785  return '/';
786 
787  case ':':
788  if(++ctx->ptr < ctx->end && *ctx->ptr == ':') {
789  ctx->ptr++;
790  return kDCOL;
791  }
792  return ':';
793 
794  case '\"':
795  case '\'':
796  return parse_string_literal(ctx, lval, *ctx->ptr);
797 
798  case '_':
799  case '$':
800  return parse_identifier(ctx, lval);
801 
802  case '@':
803  return '@';
804  }
805 
806  WARN("unexpected char '%c' %d\n", *ctx->ptr, *ctx->ptr);
807  return 0;
808 }
809 
810 struct _cc_var_t {
812  struct _cc_var_t *next;
813  unsigned name_len;
815 };
816 
818 {
819  cc_var_t *iter, *next;
820 
821  for(iter = cc->vars; iter; iter = next) {
822  next = iter->next;
823  heap_free(iter);
824  }
825 
826  heap_free(cc);
827 }
828 
829 static BOOL new_cc_var(cc_ctx_t *cc, const WCHAR *name, int len, ccval_t v)
830 {
831  cc_var_t *new_v;
832 
833  if(len == -1)
834  len = lstrlenW(name);
835 
836  new_v = heap_alloc(sizeof(cc_var_t) + (len+1)*sizeof(WCHAR));
837  if(!new_v)
838  return FALSE;
839 
840  new_v->val = v;
841  memcpy(new_v->name, name, (len+1)*sizeof(WCHAR));
842  new_v->name_len = len;
843  new_v->next = cc->vars;
844  cc->vars = new_v;
845  return TRUE;
846 }
847 
848 static cc_var_t *find_cc_var(cc_ctx_t *cc, const WCHAR *name, unsigned name_len)
849 {
850  cc_var_t *iter;
851 
852  for(iter = cc->vars; iter; iter = iter->next) {
853  if(iter->name_len == name_len && !memcmp(iter->name, name, name_len*sizeof(WCHAR)))
854  return iter;
855  }
856 
857  return NULL;
858 }
859 
861 {
862  cc_ctx_t *cc;
863 
864  if(ctx->script->cc)
865  return TRUE;
866 
867  cc = heap_alloc(sizeof(cc_ctx_t));
868  if(!cc) {
869  lex_error(ctx, E_OUTOFMEMORY);
870  return FALSE;
871  }
872 
873  cc->vars = NULL;
874 
875  if(!new_cc_var(cc, L"_jscript", -1, ccval_bool(TRUE))
876  || !new_cc_var(cc, sizeof(void*) == 8 ? L"_win64" : L"_win32", -1, ccval_bool(TRUE))
877  || !new_cc_var(cc, sizeof(void*) == 8 ? L"_amd64" : L"_x86", -1, ccval_bool(TRUE))
878  || !new_cc_var(cc, L"_jscript_version", -1, ccval_num(JSCRIPT_MAJOR_VERSION + (DOUBLE)JSCRIPT_MINOR_VERSION/10.0))
879  || !new_cc_var(cc, L"_jscript_build", -1, ccval_num(JSCRIPT_BUILD_VERSION))) {
880  release_cc(cc);
881  lex_error(ctx, E_OUTOFMEMORY);
882  return FALSE;
883  }
884 
885  ctx->script->cc = cc;
886  return TRUE;
887 }
888 
889 static BOOL parse_cc_identifier(parser_ctx_t *ctx, const WCHAR **ret, unsigned *ret_len)
890 {
891  if(*ctx->ptr != '@') {
893  return FALSE;
894  }
895 
896  if(!is_identifier_first_char(*++ctx->ptr)) {
898  return FALSE;
899  }
900 
901  *ret = ctx->ptr;
902  while(++ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr));
903  *ret_len = ctx->ptr - *ret;
904  return TRUE;
905 }
906 
908 {
909  if(!skip_spaces(ctx))
910  return -1;
911 
912  if(iswdigit(*ctx->ptr)) {
913  double n;
914 
915  if(!parse_numeric_literal(ctx, &n))
916  return -1;
917 
918  *r = ccval_num(n);
919  return 1;
920  }
921 
922  if(*ctx->ptr == '@') {
923  const WCHAR *ident;
924  unsigned ident_len;
925  cc_var_t *cc_var;
926 
927  if(!parse_cc_identifier(ctx, &ident, &ident_len))
928  return -1;
929 
930  cc_var = find_cc_var(ctx->script->cc, ident, ident_len);
931  *r = cc_var ? cc_var->val : ccval_num(NAN);
932  return 1;
933  }
934 
935  if(!check_keyword(ctx, L"true", NULL)) {
936  *r = ccval_bool(TRUE);
937  return 1;
938  }
939 
940  if(!check_keyword(ctx, L"false", NULL)) {
941  *r = ccval_bool(FALSE);
942  return 1;
943  }
944 
945  return 0;
946 }
947 
948 static int skip_code(parser_ctx_t *ctx, BOOL exec_else)
949 {
950  int if_depth = 1;
951  const WCHAR *ptr;
952 
953  while(1) {
954  ptr = wcschr(ctx->ptr, '@');
955  if(!ptr) {
956  WARN("No @end\n");
957  return lex_error(ctx, JS_E_EXPECTED_CCEND);
958  }
959  ctx->ptr = ptr+1;
960 
961  if(!check_keyword(ctx, L"end", NULL)) {
962  if(--if_depth)
963  continue;
964  return 0;
965  }
966 
967  if(exec_else && !check_keyword(ctx, L"elif", NULL)) {
968  if(if_depth > 1)
969  continue;
970 
971  if(!skip_spaces(ctx) || *ctx->ptr != '(')
972  return lex_error(ctx, JS_E_MISSING_LBRACKET);
973 
974  if(!parse_cc_expr(ctx))
975  return -1;
976 
977  if(!get_ccbool(ctx->ccval))
978  continue; /* skip block of code */
979 
980  /* continue parsing */
981  ctx->cc_if_depth++;
982  return 0;
983  }
984 
985  if(exec_else && !check_keyword(ctx, L"else", NULL)) {
986  if(if_depth > 1)
987  continue;
988 
989  /* parse else block */
990  ctx->cc_if_depth++;
991  return 0;
992  }
993 
994  if(!check_keyword(ctx, L"if", NULL)) {
995  if_depth++;
996  continue;
997  }
998 
999  ctx->ptr++;
1000  }
1001 }
1002 
1003 static int cc_token(parser_ctx_t *ctx, void *lval)
1004 {
1005  unsigned id_len = 0;
1006  cc_var_t *var;
1007 
1008  ctx->ptr++;
1009 
1010  if(!check_keyword(ctx, L"cc_on", NULL))
1011  return init_cc(ctx) ? 0 : -1;
1012 
1013  if(!check_keyword(ctx, L"set", NULL)) {
1014  const WCHAR *ident;
1015  unsigned ident_len;
1016  cc_var_t *var;
1017 
1018  if(!init_cc(ctx))
1019  return -1;
1020 
1021  if(!skip_spaces(ctx))
1022  return lex_error(ctx, JS_E_EXPECTED_AT);
1023 
1024  if(!parse_cc_identifier(ctx, &ident, &ident_len))
1025  return -1;
1026 
1027  if(!skip_spaces(ctx) || *ctx->ptr != '=')
1028  return lex_error(ctx, JS_E_EXPECTED_ASSIGN);
1029  ctx->ptr++;
1030 
1031  if(!parse_cc_expr(ctx)) {
1032  WARN("parsing CC expression failed\n");
1033  return -1;
1034  }
1035 
1036  var = find_cc_var(ctx->script->cc, ident, ident_len);
1037  if(var) {
1038  var->val = ctx->ccval;
1039  }else {
1040  if(!new_cc_var(ctx->script->cc, ident, ident_len, ctx->ccval))
1041  return lex_error(ctx, E_OUTOFMEMORY);
1042  }
1043 
1044  return 0;
1045  }
1046 
1047  if(!check_keyword(ctx, L"if", NULL)) {
1048  if(!init_cc(ctx))
1049  return -1;
1050 
1051  if(!skip_spaces(ctx) || *ctx->ptr != '(')
1052  return lex_error(ctx, JS_E_MISSING_LBRACKET);
1053 
1054  if(!parse_cc_expr(ctx))
1055  return -1;
1056 
1057  if(get_ccbool(ctx->ccval)) {
1058  /* continue parsing block inside if */
1059  ctx->cc_if_depth++;
1060  return 0;
1061  }
1062 
1063  return skip_code(ctx, TRUE);
1064  }
1065 
1066  if(!check_keyword(ctx, L"elif", NULL) || !check_keyword(ctx, L"else", NULL)) {
1067  if(!ctx->cc_if_depth)
1068  return lex_error(ctx, JS_E_SYNTAX);
1069 
1070  return skip_code(ctx, FALSE);
1071  }
1072 
1073  if(!check_keyword(ctx, L"end", NULL)) {
1074  if(!ctx->cc_if_depth)
1075  return lex_error(ctx, JS_E_SYNTAX);
1076 
1077  ctx->cc_if_depth--;
1078  return 0;
1079  }
1080 
1081  if(!ctx->script->cc)
1082  return lex_error(ctx, JS_E_DISABLED_CC);
1083 
1084  while(ctx->ptr+id_len < ctx->end && is_identifier_char(ctx->ptr[id_len]))
1085  id_len++;
1086  if(!id_len)
1087  return '@';
1088 
1089  TRACE("var %s\n", debugstr_wn(ctx->ptr, id_len));
1090 
1091  var = find_cc_var(ctx->script->cc, ctx->ptr, id_len);
1092  ctx->ptr += id_len;
1093  if(!var || var->val.is_num) {
1094  *(literal_t**)lval = new_double_literal(ctx, var ? var->val.u.n : NAN);
1095  return tNumericLiteral;
1096  }
1097 
1098  *(literal_t**)lval = new_boolean_literal(ctx, var->val.u.b);
1099  return tBooleanLiteral;
1100 }
1101 
1102 int parser_lex(void *lval, parser_ctx_t *ctx)
1103 {
1104  int ret;
1105 
1106  ctx->nl = ctx->ptr == ctx->begin;
1107 
1108  do {
1109  ret = next_token(ctx, lval);
1110  } while(ret == '@' && !(ret = cc_token(ctx, lval)));
1111 
1112  return ret;
1113 }
1114 
1116 {
1117  const WCHAR *re, *flags_ptr;
1118  BOOL in_class = FALSE;
1119  DWORD re_len, flags;
1120  literal_t *ret;
1121  HRESULT hres;
1122 
1123  TRACE("\n");
1124 
1125  while(*--ctx->ptr != '/');
1126 
1127  /* Simple regexp pre-parser; '/' if used in char class does not terminate regexp literal */
1128  re = ++ctx->ptr;
1129  while(ctx->ptr < ctx->end) {
1130  if(*ctx->ptr == '\\') {
1131  if(++ctx->ptr == ctx->end)
1132  break;
1133  }else if(in_class) {
1134  if(*ctx->ptr == '\n')
1135  break;
1136  if(*ctx->ptr == ']')
1137  in_class = FALSE;
1138  }else {
1139  if(*ctx->ptr == '/')
1140  break;
1141 
1142  if(*ctx->ptr == '[')
1143  in_class = TRUE;
1144  }
1145  ctx->ptr++;
1146  }
1147 
1148  if(ctx->ptr == ctx->end || *ctx->ptr != '/') {
1149  WARN("pre-parsing failed\n");
1150  return NULL;
1151  }
1152 
1153  re_len = ctx->ptr-re;
1154 
1155  flags_ptr = ++ctx->ptr;
1156  while(ctx->ptr < ctx->end && iswalnum(*ctx->ptr))
1157  ctx->ptr++;
1158 
1159  hres = parse_regexp_flags(flags_ptr, ctx->ptr-flags_ptr, &flags);
1160  if(FAILED(hres))
1161  return NULL;
1162 
1163  ret = parser_alloc(ctx, sizeof(literal_t));
1164  ret->type = LT_REGEXP;
1165  ret->u.regexp.str = compiler_alloc_string_len(ctx->compiler, re, re_len);
1166  ret->u.regexp.flags = flags;
1167  return ret;
1168 }
static size_t double int int int * sign
Definition: printf.c:69
HRESULT parse_regexp_flags(const WCHAR *, DWORD, DWORD *) DECLSPEC_HIDDEN
Definition: jsregexp.c:1022
#define JS_E_EXPECTED_ASSIGN
Definition: jscript.h:541
#define max(a, b)
Definition: svc.c:63
#define TRUE
Definition: types.h:120
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
#define INT_MAX
Definition: limits.h:40
static int parse_string_literal(parser_ctx_t *ctx, jsstr_t **ret, WCHAR endch)
Definition: lex.c:340
union ccval_t::@428 u
Definition: jsstr.h:39
static int hex_to_int(WCHAR c)
Definition: lex.c:118
static cc_var_t * find_cc_var(cc_ctx_t *cc, const WCHAR *name, unsigned name_len)
Definition: lex.c:848
BOOL is_identifier_char(WCHAR c)
Definition: lex.c:81
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
#define JS_E_EXPECTED_CCEND
Definition: jscript.h:549
unsigned name_len
Definition: lex.c:813
#define iswdigit(_c)
Definition: ctype.h:667
#define WARN(fmt,...)
Definition: debug.h:111
HRESULT parse_decimal(const WCHAR **iter, const WCHAR *end, double *ret)
Definition: lex.c:397
GLdouble n
Definition: glext.h:7729
static int parse_identifier(parser_ctx_t *ctx, const WCHAR **ret)
Definition: lex.c:321
BOOL is_num
Definition: parser.h:26
#define iswalpha(_c)
Definition: ctype.h:664
int try_parse_ccval(parser_ctx_t *ctx, ccval_t *r)
Definition: lex.c:907
static BOOL parse_numeric_literal(parser_ctx_t *ctx, double *ret)
Definition: lex.c:473
literal_t * new_boolean_literal(parser_ctx_t *ctx, BOOL bval)
Definition: lex.c:387
Definition: parser.h:75
GLuint GLuint end
Definition: gl.h:1545
#define MAXLONGLONG
static ccval_t ccval_bool(BOOL b)
Definition: parser.h:387
#define in_class(found, pat, c)
Definition: match.c:168
#define JSCRIPT_MAJOR_VERSION
Definition: resource.h:23
#define lstrlenW
Definition: compat.h:415
#define E_FAIL
Definition: ddrawi.h:102
static literal_t * new_double_literal(parser_ctx_t *ctx, DOUBLE d)
Definition: lex.c:378
static void * heap_alloc(size_t len)
Definition: appwiz.h:65
#define JSCRIPT_BUILD_VERSION
Definition: resource.h:25
void release_cc(cc_ctx_t *cc)
Definition: lex.c:817
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
WCHAR name[0]
Definition: lex.c:814
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
int token
Definition: lex.c:37
unsigned int BOOL
Definition: ntddk_ex.h:94
float pow(float __x, int __y)
Definition: _cmath.h:458
#define iswalnum(_c)
Definition: ctype.h:671
#define e
Definition: ke_i.h:82
#define debugstr_w
Definition: kernel32.h:32
static PVOID ptr
Definition: dispmode.c:27
static ccval_t ccval_num(double n)
Definition: parser.h:379
const WCHAR * str
const WCHAR * ptr
Definition: parse.h:261
smooth NULL
Definition: ftsmooth.c:416
#define JS_E_MISSING_LBRACKET
Definition: jscript.h:538
static int skip_code(parser_ctx_t *ctx, BOOL exec_else)
Definition: lex.c:948
BOOL parse_cc_expr(parser_ctx_t *ctx)
static int cc_token(parser_ctx_t *ctx, void *lval)
Definition: lex.c:1003
literal_t * parse_regexp(parser_ctx_t *ctx)
Definition: lex.c:1115
GLuint GLfloat * val
Definition: glext.h:7180
_In_ ULONG _In_ ULONG_PTR ident
Definition: winddi.h:3993
BOOL no_nl
Definition: lex.c:38
int64_t LONGLONG
Definition: typedefs.h:66
BOOL b
Definition: parser.h:28
#define TRACE(s)
Definition: solgame.cpp:4
HRESULT hres
Definition: protocol.c:465
#define d
Definition: ke_i.h:81
_CONST_RETURN wchar_t *__cdecl wcschr(_In_z_ const wchar_t *_Str, wchar_t _Ch)
__wchar_t WCHAR
Definition: xmlstorage.h:180
LONG HRESULT
Definition: typedefs.h:77
static int check_keywords(parser_ctx_t *ctx, const WCHAR **lval)
Definition: lex.c:132
const GLubyte * c
Definition: glext.h:8905
unsigned long DWORD
Definition: ntddk_ex.h:95
ccval_t val
Definition: lex.c:811
#define NAN
Definition: misc.c:46
static BOOL skip_html_comment(parser_ctx_t *ctx)
Definition: lex.c:160
struct _cc_var_t * next
Definition: lex.c:812
static JOBOBJECTINFOCLASS LPVOID DWORD LPDWORD ret_len
Definition: process.c:79
GLbitfield flags
Definition: glext.h:7161
#define SCRIPTLANGUAGEVERSION_ES5
Definition: jscript.h:52
#define JS_E_MISSING_SEMICOLON
Definition: jscript.h:537
#define iswspace(_c)
Definition: ctype.h:669
int ret
#define JS_E_DISABLED_CC
Definition: jscript.h:550
unsigned min_version
Definition: lex.c:39
static int lex_error(parser_ctx_t *ctx, HRESULT hres)
Definition: lex.c:73
static const WCHAR L[]
Definition: oid.c:1250
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
jsstr_t * compiler_alloc_string_len(compiler_ctx_t *ctx, const WCHAR *str, unsigned len)
Definition: compile.c:133
const WCHAR * end
Definition: parse.h:262
static INT ident_len(LPCTSTR p)
Definition: set.c:208
static BOOL is_endline(WCHAR c)
Definition: lex.c:113
static BOOL init_cc(parser_ctx_t *ctx)
Definition: lex.c:860
#define debugstr_wn
Definition: kernel32.h:33
static BOOL parse_cc_identifier(parser_ctx_t *ctx, const WCHAR **ret, unsigned *ret_len)
Definition: lex.c:889
#define INT_MIN
Definition: limits.h:39
#define JS_E_UNTERMINATED_STRING
Definition: jscript.h:543
#define ERR(fmt,...)
Definition: debug.h:109
uint32_t cc
Definition: isohybrid.c:75
static BOOL is_identifier_first_char(WCHAR c)
Definition: lex.c:86
static void * parser_alloc(parser_ctx_t *ctx, DWORD size)
Definition: parser.h:58
double n
Definition: parser.h:29
#define S_OK
Definition: intsafe.h:59
static unsigned __int64 next
Definition: rand_nt.c:6
#define JS_E_EXPECTED_AT
Definition: jscript.h:551
const GLdouble * v
Definition: gl.h:2040
#define JSCRIPT_MINOR_VERSION
Definition: resource.h:24
#define ARRAY_SIZE(a)
Definition: main.h:24
static int next_token(parser_ctx_t *ctx, void *lval)
Definition: lex.c:546
Definition: lex.c:810
int parser_lex(void *lval, parser_ctx_t *ctx)
Definition: lex.c:1102
static BOOL get_ccbool(ccval_t v)
Definition: parser.h:395
#define min(a, b)
Definition: monoChain.cc:55
static BOOL skip_spaces(parser_ctx_t *ctx)
Definition: lex.c:217
BOOL unescape(WCHAR *str, size_t *len)
Definition: lex.c:227
DWORD exp
Definition: msg.c:16038
Definition: parser.h:25
const WCHAR * word
Definition: lex.c:36
#define JS_E_SYNTAX
Definition: jscript.h:536
Definition: name.c:38
static BOOL skip_comment(parser_ctx_t *ctx)
Definition: lex.c:174
#define c
Definition: ke_i.h:80
double DOUBLE
Definition: typedefs.h:68
float bval
Definition: cylfrac.c:48
#define JS_E_EXPECTED_IDENTIFIER
Definition: jscript.h:540
HRESULT hres
Definition: parse.h:267
GLfloat GLfloat p
Definition: glext.h:8902
BOOL is_html
Definition: parse.h:266
static const struct @427 keywords[]
static BOOL new_cc_var(cc_ctx_t *cc, const WCHAR *name, int len, ccval_t v)
Definition: lex.c:829
WINE_DEFAULT_DEBUG_CHANNEL(jscript)
static int check_keyword(parser_ctx_t *ctx, const WCHAR *word, const WCHAR **lval)
Definition: lex.c:91
static BOOL heap_free(void *mem)
Definition: appwiz.h:75