1 /* libsswf_as.h -- written by Alexis WILKE for Made to Order Software Corp. (c) 2005-2009 */
2 #ifndef LIBSSWF_AS_H
3 #define LIBSSWF_AS_H
4
5 /*
6
7 Copyright (c) 2005-2009 Made to Order Software Corp.
8
9 Permission is hereby granted, free of charge, to any
10 person obtaining a copy of this software and
11 associated documentation files (the "Software"), to
12 deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify,
14 merge, publish, distribute, sublicense, and/or sell
15 copies of the Software, and to permit persons to whom
16 the Software is furnished to do so, subject to the
17 following conditions:
18
19 The above copyright notice and this permission notice
20 shall be included in all copies or substantial
21 portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
24 ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
25 LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
26 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
27 EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
29 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
30 ARISING FROM, OUT OF OR IN CONNECTION WITH THE
31 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 SOFTWARE.
33
34 */
35
36
37
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <time.h>
42 #ifdef _MSVC
43 #include <io.h>
44 #include <float.h>
45 #include <direct.h>
46 #include <limits.h>
47 #define snprintf _snprintf
48 #define vsnprintf _vsnprintf
mkdir(const char * filename)49 inline int mkdir(const char *filename) { return _mkdir(filename); }
isnan(double nan)50 inline int isnan(double nan) { return _isnan(nan); }
isinf(double d)51 inline int isinf(double d)
52 {
53 int c;
54 c = _fpclass(d);
55 if(c == _FPCLASS_PINF) {
56 return 1;
57 }
58 else if(c == _FPCLASS_NINF) {
59 return -1;
60 }
61 return 0;
62 }
63 typedef __int64 int64_t;
64 typedef unsigned __int64 uint64_t;
65 typedef __int32 int32_t;
66 typedef unsigned __int32 uint32_t;
strtoll(const char * str,char * end,int base)67 inline int64_t strtoll(const char *str, char *end, int base)
68 {
69 return _atoi64(str);
70 }
71 #else
72 #include <inttypes.h>
73 #include <unistd.h>
74 #include <dirent.h>
75 #endif
76 #include <string.h>
77 #include <math.h>
78 #include <limits.h>
79 #include <sys/stat.h>
80
81 #include "sswf/libsswf-config.h"
82
83
84 #ifdef NEED_FP_NAN
85 #ifndef FP_NAN
86 static union __nan_value { uint32_t __l; float __d; } __nan_union = { 0x7fc00000UL };
87 #define FP_NAN (__nan_union.__d)
88 #endif
89 #endif
90 #ifdef NEED_ISINF
91 #if IRIX
92 // my old version (6.5.7) doesn't have a correct isinf() function
93 // if you have a newer version and you are sure you have a proper
94 // version of isinf(), then feel free to remove this declaration
95 #include <fp_class.h>
isinf(double d)96 static int isinf(double d)
97 {
98 int c;
99 c = fp_class_d(d);
100 if(c == FP_POS_INF) {
101 return 1;
102 }
103 else if(c == FP_NEG_INF) {
104 return -1;
105 }
106 return 0;
107 }
108 #endif
109 #endif
110
111
112
113
114 namespace sswf
115 {
116 namespace as
117 {
118
119
120
121 #if defined(_DEBUG) || defined(DEBUG)
122 #define AS_ASSERT(test) { if(!(test)) printf("FATAL ERROR: AS_ASSERT(" #test ") is false in " __FILE__ " at line %d.\n", __LINE__), abort(); }
123 #else
124 #define AS_ASSERT(test)
125 #endif
126
127
128 enum err_code_t
129 {
130 AS_ERR_NONE = 0,
131
132 AS_ERR_ABSTRACT,
133 AS_ERR_BAD_PRAGMA,
134 AS_ERR_CANNOT_MATCH,
135 AS_ERR_CANNOT_OVERLOAD,
136 AS_ERR_CANNOT_OVERWRITE_CONST,
137 AS_ERR_CASE_LABEL,
138 AS_ERR_COLON_EXPECTED,
139 AS_ERR_CURVLY_BRAKETS_EXPECTED,
140 AS_ERR_DEFAULT_LABEL,
141 AS_ERR_DIVIDE_BY_ZERO,
142 AS_ERR_DUPLICATES,
143 AS_ERR_DYNAMIC,
144 AS_ERR_FINAL,
145 AS_ERR_IMPORPER_STATEMENT,
146 AS_ERR_INACCESSIBLE_STATEMENT,
147 AS_ERR_INCOMPATIBLE,
148 AS_ERR_INCOMPATIBLE_PRAGMA_ARGUMENT,
149 AS_ERR_INSTANCE_EXPECTED,
150 AS_ERR_INTERNAL_ERROR,
151 AS_ERR_INTRINSIC,
152 AS_ERR_INVALID_ARRAY_FUNCTION,
153 AS_ERR_INVALID_ATTRIBUTES,
154 AS_ERR_INVALID_CATCH,
155 AS_ERR_INVALID_CLASS,
156 AS_ERR_INVALID_CONDITIONAL,
157 AS_ERR_INVALID_DEFINITION,
158 AS_ERR_INVALID_DO,
159 AS_ERR_INVALID_ENUM,
160 AS_ERR_INVALID_EXPRESSION,
161 AS_ERR_INVALID_FIELD,
162 AS_ERR_INVALID_FIELD_NAME,
163 AS_ERR_INVALID_FRAME,
164 AS_ERR_INVALID_FUNCTION,
165 AS_ERR_INVALID_GOTO,
166 AS_ERR_INVALID_KEYWORD,
167 AS_ERR_INVALID_LABEL,
168 AS_ERR_INVALID_NAMESPACE,
169 AS_ERR_INVALID_NODE,
170 AS_ERR_INVALID_OPERATOR,
171 AS_ERR_INVALID_PACKAGE_NAME,
172 AS_ERR_INVALID_PARAMETERS,
173 AS_ERR_INVALID_REST,
174 AS_ERR_INVALID_RETURN_TYPE,
175 AS_ERR_INVALID_SCOPE,
176 AS_ERR_INVALID_TRY,
177 AS_ERR_INVALID_TYPE,
178 AS_ERR_INVALID_UNICODE_ESCAPE_SEQUENCE,
179 AS_ERR_INVALID_VARIABLE,
180 AS_ERR_LABEL_NOT_FOUND,
181 AS_ERR_LOOPING_REFERENCE,
182 AS_ERR_MISMATCH_FUNC_VAR,
183 AS_ERR_NEED_CONST,
184 AS_ERR_NOT_FOUND,
185 AS_ERR_NOT_SUPPORTED,
186 AS_ERR_PARENTHESIS_EXPECTED,
187 AS_ERR_PRAGMA_FAILED,
188 AS_ERR_SEMICOLON_EXPECTED,
189 AS_ERR_SQUARE_BRAKETS_EXPECTED,
190 AS_ERR_STATIC,
191 AS_ERR_UNKNOWN_ESCAPE_SEQUENCE,
192 AS_ERR_UNKNOWN_OPERATOR,
193 AS_ERR_UNTERMINTED_STRING,
194 AS_ERR_UNEXPECTED_PUNCTUATION,
195
196 AS_ERR_max
197 };
198
199
200
201 class Node;
202
203 // the node type is often referenced as a token
204 enum node_t
205 {
206 NODE_EOF = -1, // when reading after the end of the file
207 NODE_UNKNOWN = 0, // node still uninitialized
208
209 // here are all the punctuation as themselves
210 // (i.e. '<', '>', '=', '+', '-', etc.)
211 NODE_ADD = '+',
212 NODE_BITWISE_AND = '&',
213 NODE_BITWISE_NOT = '~',
214 NODE_ASSIGNMENT = '=',
215 NODE_BITWISE_OR = '|',
216 NODE_BITWISE_XOR = '^',
217 NODE_CLOSE_CURVLY_BRACKET = '}',
218 NODE_CLOSE_PARENTHESIS = ')',
219 NODE_CLOSE_SQUARE_BRACKET = ']',
220 NODE_COLON = ':',
221 NODE_COMMA = ',',
222 NODE_CONDITIONAL = '?',
223 NODE_DIVIDE = '/',
224 NODE_GREATER = '>',
225 NODE_LESS = '<',
226 NODE_LOGICAL_NOT = '!',
227 NODE_MODULO = '%',
228 NODE_MULTIPLY = '*',
229 NODE_OPEN_CURVLY_BRACKET = '{',
230 NODE_OPEN_PARENTHESIS = '(',
231 NODE_OPEN_SQUARE_BRACKET = '[',
232 NODE_MEMBER = '.',
233 NODE_SEMICOLON = ';',
234 NODE_SUBTRACT = '-',
235
236 // The following are composed tokens
237 // (operators, keywords, strings, numbers...)
238 NODE_other = 1000,
239
240 NODE_ARRAY,
241 NODE_ARRAY_LITERAL,
242 NODE_AS,
243 NODE_ASSIGNMENT_ADD,
244 NODE_ASSIGNMENT_BITWISE_AND,
245 NODE_ASSIGNMENT_BITWISE_OR,
246 NODE_ASSIGNMENT_BITWISE_XOR,
247 NODE_ASSIGNMENT_DIVIDE,
248 NODE_ASSIGNMENT_LOGICAL_AND,
249 NODE_ASSIGNMENT_LOGICAL_OR,
250 NODE_ASSIGNMENT_LOGICAL_XOR,
251 NODE_ASSIGNMENT_MAXIMUM,
252 NODE_ASSIGNMENT_MINIMUM,
253 NODE_ASSIGNMENT_MODULO,
254 NODE_ASSIGNMENT_MULTIPLY,
255 NODE_ASSIGNMENT_POWER,
256 NODE_ASSIGNMENT_ROTATE_LEFT,
257 NODE_ASSIGNMENT_ROTATE_RIGHT,
258 NODE_ASSIGNMENT_SHIFT_LEFT,
259 NODE_ASSIGNMENT_SHIFT_RIGHT,
260 NODE_ASSIGNMENT_SHIFT_RIGHT_UNSIGNED,
261 NODE_ASSIGNMENT_SUBTRACT,
262 NODE_ATTRIBUTES,
263 NODE_AUTO,
264 NODE_BREAK,
265 NODE_CALL,
266 NODE_CASE,
267 NODE_CATCH,
268 NODE_CLASS,
269 NODE_CONST,
270 NODE_CONTINUE,
271 NODE_DEBUGGER,
272 NODE_DECREMENT,
273 NODE_DEFAULT,
274 NODE_DELETE,
275 NODE_DIRECTIVE_LIST,
276 NODE_DO,
277 NODE_ELSE,
278 NODE_EMPTY,
279 NODE_ENTRY,
280 NODE_ENUM,
281 NODE_EQUAL,
282 NODE_EXCLUDE,
283 NODE_EXTENDS,
284 NODE_FALSE,
285 NODE_FINALLY,
286 NODE_FLOAT64,
287 NODE_FOR,
288 NODE_FOR_IN,
289 NODE_FUNCTION,
290 NODE_GOTO,
291 NODE_GREATER_EQUAL,
292 NODE_IDENTIFIER,
293 NODE_IF,
294 NODE_IMPLEMENTS,
295 NODE_IMPORT,
296 NODE_IN,
297 NODE_INCLUDE,
298 NODE_INCREMENT,
299 NODE_INSTANCEOF,
300 NODE_INT64,
301 NODE_INTERFACE,
302 NODE_IS,
303 NODE_LABEL,
304 NODE_LESS_EQUAL,
305 NODE_LIST,
306 NODE_LOGICAL_AND,
307 NODE_LOGICAL_OR,
308 NODE_LOGICAL_XOR,
309 NODE_MATCH,
310 NODE_MAXIMUM,
311 NODE_MINIMUM,
312 NODE_NAME,
313 NODE_NAMESPACE,
314 NODE_NEW,
315 NODE_NOT_EQUAL,
316 NODE_NULL,
317 NODE_OBJECT_LITERAL,
318 NODE_PACKAGE,
319 NODE_PARAM,
320 NODE_PARAMETERS,
321 NODE_PARAM_MATCH,
322 NODE_POST_DECREMENT,
323 NODE_POST_INCREMENT,
324 NODE_POWER,
325 NODE_PRIVATE,
326 NODE_PROGRAM,
327 NODE_PUBLIC,
328 NODE_RANGE,
329 NODE_REGULAR_EXPRESSION,
330 NODE_REST,
331 NODE_RETURN,
332 NODE_ROOT,
333 NODE_ROTATE_LEFT,
334 NODE_ROTATE_RIGHT,
335 NODE_SCOPE,
336 NODE_SET,
337 NODE_SHIFT_LEFT,
338 NODE_SHIFT_RIGHT,
339 NODE_SHIFT_RIGHT_UNSIGNED,
340 NODE_STRICTLY_EQUAL,
341 NODE_STRICTLY_NOT_EQUAL,
342 NODE_STRING,
343 NODE_SUPER,
344 NODE_SWITCH,
345 NODE_THIS,
346 NODE_THROW,
347 NODE_TRUE,
348 NODE_TRY,
349 NODE_TYPE,
350 NODE_TYPEOF,
351 NODE_UNDEFINED,
352 NODE_USE,
353 NODE_VAR,
354 NODE_VARIABLE,
355 NODE_VAR_ATTRIBUTES,
356 NODE_VIDENTIFIER,
357 NODE_VOID,
358 NODE_WHILE,
359 NODE_WITH,
360
361 NODE_max, // mark the limit
362
363 // used to extract the node type from some integers
364 // (used by the SWITCH statement at time of writing)
365 NODE_MASK = 0x0FFFF
366 };
367
368
369
370
371
372 // some nodes use flags as defined below:
373 enum flags_t
374 {
375 // NODE_CATCH
376 NODE_CATCH_FLAG_TYPED = 0x01,
377
378 // NODE_DIRECTIVE_LIST
379 NODE_DIRECTIVE_LIST_FLAG_NEW_VARIABLES = 0x01,
380
381 // NODE_FOR
382 NODE_FOR_FLAG_FOREACH = 0x01,
383
384 // NODE_FUNCTION
385 NODE_FUNCTION_FLAG_GETTER = 0x01,
386 NODE_FUNCTION_FLAG_SETTER = 0x02,
387 NODE_FUNCTION_FLAG_OUT = 0x04,
388 NODE_FUNCTION_FLAG_VOID = 0x08,
389 NODE_FUNCTION_FLAG_NEVER = 0x10,
390 NODE_FUNCTION_FLAG_NOPARAMS = 0x20,
391 NODE_FUNCTION_FLAG_OPERATOR = 0x40,
392
393 // NODE_IDENTIFIER, NODE_VIDENTIFIER, NODE_STRING
394 NODE_IDENTIFIER_FLAG_WITH = 0x01,
395 NODE_IDENTIFIER_FLAG_TYPED = 0x02,
396
397 // NODE_IMPORT
398 NODE_IMPORT_FLAG_IMPLEMENTS = 0x01,
399
400 // NODE_PACKAGE
401 NODE_PACKAGE_FLAG_FOUND_LABELS = 0x01,
402 NODE_PACKAGE_FLAG_REFERENCED = 0x02,
403
404 // NODE_PARAM_MATCH
405 NODE_PARAM_MATCH_FLAG_UNPROTOTYPED = 0x01,
406
407 // NODE_PARAMETERS
408 NODE_PARAMETERS_FLAG_CONST = 0x001,
409 NODE_PARAMETERS_FLAG_IN = 0x002,
410 NODE_PARAMETERS_FLAG_OUT = 0x004,
411 NODE_PARAMETERS_FLAG_NAMED = 0x008,
412 NODE_PARAMETERS_FLAG_REST = 0x010,
413 NODE_PARAMETERS_FLAG_UNCHECKED = 0x020,
414 NODE_PARAMETERS_FLAG_UNPROTOTYPED = 0x040,
415 NODE_PARAMETERS_FLAG_REFERENCED = 0x080, // referenced from a parameter or a variable
416 NODE_PARAMETERS_FLAG_PARAMREF = 0x100, // referenced from another parameter
417 NODE_PARAMETERS_FLAG_CATCH = 0x200, // a parameter defined in a catch()
418
419 // NODE_SWITCH
420 // WARNING: the switch() integer is also used for the operator node type
421 NODE_SWITCH_FLAG_DEFAULT = 0x80000000, // we found a 'default:' label in that switch
422
423 // NODE_VARIABLE (and NODE_VAR, NODE_PARAM)
424 NODE_VAR_FLAG_CONST = 0x01,
425 NODE_VAR_FLAG_LOCAL = 0x02,
426 NODE_VAR_FLAG_MEMBER = 0x04,
427 NODE_VAR_FLAG_ATTRIBUTES = 0x08,
428 NODE_VAR_FLAG_ENUM = 0x02000000, // there is a NODE_SET and it somehow needs to be copied
429 NODE_VAR_FLAG_COMPILED = 0x04000000, // Expression() was called on the NODE_SET
430 NODE_VAR_FLAG_INUSE = 0x08000000, // this variable was referenced
431 NODE_VAR_FLAG_ATTRS = 0x10000000, // currently being read for attributes (to avoid loops)
432 NODE_VAR_FLAG_DEFINED = 0x20000000, // was already parsed
433 NODE_VAR_FLAG_DEFINING = 0x40000000, // currently defining, can't read
434 NODE_VAR_FLAG_TOADD = 0x80000000, // to be added in the directive list
435
436 unused_flag // enables commas on all flags...
437 };
438
439
440 // the following is a list of all the possible attributes in our system
441 // (note that the bits may change in the future)
442 // member visibility
443 static const unsigned long NODE_ATTR_PUBLIC = 0x00000001;
444 static const unsigned long NODE_ATTR_PRIVATE = 0x00000002;
445 static const unsigned long NODE_ATTR_PROTECTED = 0x00000004;
446 static const unsigned long NODE_ATTR_INTERNAL = 0x00000008;
447
448 // function member type
449 static const unsigned long NODE_ATTR_STATIC = 0x00000010;
450 static const unsigned long NODE_ATTR_ABSTRACT = 0x00000020;
451 static const unsigned long NODE_ATTR_VIRTUAL = 0x00000040;
452 static const unsigned long NODE_ATTR_ARRAY = 0x00000080;
453
454 // function/variable is defined in your system (execution env.)
455 // you won't find a body for these functions; the variables
456 // will likely be read-only
457 static const unsigned long NODE_ATTR_INTRINSIC = 0x00000100;
458
459 // operator overload (function member)
460 // Contructor -> another way to construct this type of objects
461 static const unsigned long NODE_ATTR_CONSTRUCTOR = 0x00000200;
462
463 // function & member constrains
464 // CONST is not currently available as an attribute (see flags instead)
465 //static const unsigned long NODE_ATTR_CONST = 0x00001000;
466 static const unsigned long NODE_ATTR_FINAL = 0x00002000;
467 static const unsigned long NODE_ATTR_ENUMERABLE = 0x00004000;
468
469 // conditional compilation
470 static const unsigned long NODE_ATTR_TRUE = 0x00010000;
471 static const unsigned long NODE_ATTR_FALSE = 0x00020000;
472 static const unsigned long NODE_ATTR_UNUSED = 0x00040000; // if definition is used, error!
473
474 // class attribute (whether a class can be enlarged at run time)
475 static const unsigned long NODE_ATTR_DYNAMIC = 0x00100000;
476
477 // switch attributes
478 static const unsigned long NODE_ATTR_FOREACH = 0x01000000;
479 static const unsigned long NODE_ATTR_NOBREAK = 0x02000000;
480 static const unsigned long NODE_ATTR_AUTOBREAK = 0x04000000;
481
482 // The following is to make sure we never define the attributes more
483 // than once.
484 static const unsigned long NODE_ATTR_DEFINED = 0x80000000;
485
486
487
488
489 class String
490 {
491 public:
492 String(void);
493 String(const String& string);
494 String(const char *str);
495 ~String();
496
497 String& operator = (const String& string);
498
499 // Assume ISO-8859-1 as input
500 String& operator = (const char *str);
501
502 bool operator == (const String& string) const;
503 bool operator != (const String& string) const;
504 bool operator == (const char *str) const;
505 bool operator != (const char *str) const;
506 String& operator += (const String& string);
507 // Assume ISO-8859-1 as input
508 String& operator += (const char *str);
509
510 int Compare(const String& string) const;
511 int Compare(const char *string) const;
512 bool IsEmpty(void) const;
513 void Empty(void);
514 long GetLength(void) const;
515 const long * Get(void) const; // NOT NULL TERMINATED
516 void Set(const long *str, long size);
517 void AppendChar(long c);
518 String& AppendStr(const long *str, long len);
519 int GetUTF8Length(void) const;
520 int ToUTF8(char *mb, size_t& mb_len) const; // -1 on error, 0 otherwise
521 int FromUTF8(const char *mb, size_t mb_len); // -1 on error, 0 otherwise
522
523 // WARNING: you need to 'delete [] str' of returned pointer
524 char * GetUTF8(void) const;
525
526 private:
527 long f_len;
528 long f_max;
529 long * f_str;
530 };
531
532 class Int64
533 {
534 public:
Int64(void)535 Int64(void)
536 {
537 f_int = 0;
538 }
Int64(const Int64 & src_int)539 Int64(const Int64& src_int)
540 {
541 f_int = src_int.f_int;
542 }
543
544 Int64& operator = (const Int64& src_int)
545 {
546 f_int = src_int.f_int;
547 return *this;
548 }
549
Get(void)550 int64_t Get(void) const
551 {
552 return f_int;
553 }
Set(int64_t new_int)554 void Set(int64_t new_int)
555 {
556 f_int = new_int;
557 }
558
559 private:
560 int64_t f_int;
561 };
562
563
564 class Float64
565 {
566 public:
Float64(void)567 Float64(void)
568 {
569 f_float = 0;
570 }
Float64(const Float64 & src_float)571 Float64(const Float64& src_float)
572 {
573 f_float = src_float.f_float;
574 }
575
576 Float64& operator = (const Float64& src_float)
577 {
578 f_float = src_float.f_float;
579 return *this;
580 }
581
Get(void)582 double Get(void) const
583 {
584 return f_float;
585 }
Set(double new_float)586 void Set(double new_float)
587 {
588 f_float = new_float;
589 }
590
591 private:
592 double f_float;
593 };
594
595
596 class UserData
597 {
598 public:
UserData(void)599 UserData(void)
600 {
601 f_size = 0;
602 f_data = 0;
603 }
UserData(const UserData & src)604 UserData(const UserData& src)
605 {
606 if(src.f_size > 0) {
607 f_data = 0;
608 New(src.f_size);
609 memcpy(f_data, src.f_data, sizeof(int) * f_size);
610 }
611 else {
612 f_size = 0;
613 f_data = 0;
614 }
615 }
~UserData()616 ~UserData()
617 {
618 delete [] f_data;
619 }
620 UserData& operator = (const UserData& src)
621 {
622 delete [] f_data;
623 if(src.f_size > 0) {
624 f_data = 0;
625 New(src.f_size);
626 memcpy(f_data, src.f_data, sizeof(int) * f_size);
627 }
628 else {
629 f_size = 0;
630 f_data = 0;
631 }
632 return *this;
633 }
New(int size)634 void New(int size)
635 {
636 AS_ASSERT(size >= 0);
637 delete [] f_data;
638 if(size > 0) {
639 f_data = new int[size];
640 // by default we clear it
641 memset(f_data, 0, sizeof(int) * size);
642 }
643 else {
644 f_data = 0;
645 }
646 f_size = size;
647 }
648
Size(void)649 int Size(void) const
650 {
651 return f_size;
652 }
Buffer(void)653 int * Buffer(void)
654 {
655 // we want to make sure that each call
656 // to Buffer doesn't require this test
657 AS_ASSERT(f_data != 0);
658 return f_data;
659 }
Buffer(void)660 const int * Buffer(void) const
661 {
662 // we want to make sure that each call
663 // to Buffer doesn't require this test
664 AS_ASSERT(f_data != 0);
665 return f_data;
666 }
667
668 private:
669 int f_size;
670 int * f_data;
671 };
672
673
674 struct Data
675 {
DataData676 Data(void)
677 {
678 f_type = NODE_UNKNOWN;
679 }
ClearData680 void Clear(void)
681 {
682 f_type = NODE_UNKNOWN;
683 f_int.Set(0);
684 f_float.Set(0.0);
685 f_str.Empty();
686 }
687 void Display(FILE *out) const;
688 const char * GetTypeName(void) const;
689
690 // basic conversions
691 bool ToBoolean(void);
692 bool ToNumber(void);
693 bool ToString(void);
694
695 node_t f_type;
696 Int64 f_int;
697 Float64 f_float;
698 String f_str;
699 UserData f_user_data;
700 };
701
702
703
704 class Input;
705 class NodePtr
706 {
707 public:
708 enum link_t {
709 LINK_INSTANCE = 0,
710 LINK_TYPE,
711 LINK_ATTRIBUTES, // this is the list of identifiers
712
713 LINK_max,
714
715 LINK_GOTO_EXIT = LINK_INSTANCE,
716 LINK_GOTO_ENTER = LINK_TYPE,
717
718 LINK_end
719 };
720
NodePtr(void)721 NodePtr(void)
722 {
723 f_node = 0;
724 }
725 NodePtr(const NodePtr& node);
726 ~NodePtr();
727
728 NodePtr& operator = (const NodePtr& node);
729
730 void SetInputInfo(const Input *input);
731 void CopyInputInfo(const NodePtr& node);
732 long GetPage(void) const;
733 long GetPageLine(void) const;
734 long GetParagraph(void) const;
735 long GetLine(void) const;
736 const String& GetFilename(void) const;
737
738 void SetNode(const Node *node);
739 void SetNode(const NodePtr& node);
740 void CreateNode(node_t type = NODE_UNKNOWN);
741 NodePtr& Clone(const NodePtr& source);
742 void ClearNode(void);
HasNode(void)743 bool HasNode(void) const
744 {
745 return f_node != 0;
746 }
SameAs(const NodePtr & node)747 bool SameAs(const NodePtr& node) const
748 {
749 return f_node == node.f_node;
750 }
751
752 Data& GetData(void) const;
753 void SetData(const Data& data);
754 unsigned long GetAttrs(void) const; // see NODE_ATTR_...
755 void SetAttrs(unsigned long attrs);
756 bool HasSideEffects(void) const;
757
758 bool IsLocked(void) const;
759 void Lock(void);
760 void Unlock(void);
761 void SetOffset(int offset);
762 int GetOffset(void) const;
763 void ReplaceWith(NodePtr& new_node);
764 void DeleteChild(int index);
765 void AddChild(NodePtr& child);
766 void InsertChild(int idx, NodePtr& child);
767 void SetChild(int index, NodePtr& child);
768 int GetChildCount(void) const;
769 NodePtr& GetChild(int index) const;
770 void SetParent(Node *parent);
771 NodePtr& GetParent(void);
772 void SetLink(link_t index, NodePtr& link);
773 NodePtr& GetLink(link_t index);
774
775 void AddVariable(NodePtr& variable);
776 int GetVariableCount(void) const;
777 NodePtr& GetVariable(int index) const;
778
779 void AddLabel(NodePtr& label);
780 int GetLabelCount(void) const;
781 NodePtr& GetLabel(int index) const;
782 NodePtr& FindLabel(const String& name) const;
783
784 void Display(FILE *out, int indent = 0, NodePtr *parent = 0, char c = '-') const;
785 void DisplayPtr(FILE *out) const;
786
787 const char * OperatorToString(void);
788 node_t StringToOperator(void);
789
790 private:
791 Node * f_node;
792 };
793
794
795 class NodeLock
796 {
797 public:
NodeLock(NodePtr & node)798 NodeLock(NodePtr& node)
799 {
800 f_node = node;
801 if(f_node.HasNode()) {
802 f_node.Lock();
803 }
804 }
~NodeLock()805 ~NodeLock()
806 {
807 if(f_node.HasNode()) {
808 f_node.Unlock();
809 }
810 }
811
812 // premature unlocking
Unlock(void)813 void Unlock(void)
814 {
815 if(f_node.HasNode()) {
816 f_node.Unlock();
817 f_node.ClearNode();
818 }
819 }
820
821 private:
822 NodePtr f_node;
823 };
824
825
826
827 // ErrorStream handling object; you can derive from this
828 // class to redirect the errors to a different
829 // output (by default it goes to stderr).
830 // For that purpose, overload the Error() function.
831 // Within your function, use the IntGetFilename()
832 // and IntLine() functions to get the filename
833 // and line where the error occured.
834 //
835 // NOTE: The Input class derives from this class
836 // so it can handle the errors at once.
837 class ErrorStream
838 {
839 public:
840 ErrorStream(void);
841 virtual ~ErrorStream();
842
843 // by default, write in stderr; overload to send errors in
844 // your console, etc.
845 virtual void Error(err_code_t err_code, const char *message);
846
847 // We call one of these functions which transform their
848 // parameters (format + params) in a single easy to use
849 // string sent to Error().
850 // You don't overload these functions.
851 void ErrMsg(err_code_t err_code, const char *format, ...);
852 void ErrMsg(err_code_t err_code, const char *format, va_list ap);
853
854 // the following replaces String pointers by their UTF-8 const char *
855 // whenever the format includes a %S -- this makes it work on all
856 // systems without jungling with wide characters too much
857 // also, we support %N for nodes in which case we print out the
858 // filename and line of the given node
859 void ErrStrMsg(err_code_t err_code, const char *format, ...);
860 void ErrStrMsg(err_code_t err_code, const char *format, va_list ap);
861
862 // errors which should use the node information for the
863 // filename & line number (instead of GetFilename() and Line())
864 void ErrMsg(err_code_t err_code, const NodePtr& node, const char *format, ...);
865 void ErrStrMsg(err_code_t err_code, const NodePtr& node, const char *format, ...);
866
ErrCount(void)867 long ErrCount(void) const
868 {
869 return f_errcnt;
870 }
871
872 virtual const char * GetFilename(void) const;
873 virtual long Line(void) const;
874
875 protected:
876 const String& IntGetFilename(void) const;
877 long IntLine(void) const;
878
879 private:
880 long f_errcnt;
881 NodePtr f_node;
882 mutable String f_filename; // IntGetFilename() must return a string...
883 };
884
885
886
887 // I/O interface that YOU have to derive from so the
888 // parser can read the input data from somewhere
889 // You need to implement the GetC() function. You can
890 // also overload the Error() function so it prints
891 // the errors in a console of your choice.
892 // The GetFilename() is used by the default Error()
893 // function. It is used to generate an error like gcc.
894 // That function returns "asc" by default.
895 //
896 // Two examples are available below. One reads a USC-4
897 // formatted file and the other reads a string.
898 class Input : public ErrorStream
899 {
900 public:
901 enum {
902 AS_EOF = -1
903 };
904
905 Input(void);
906 virtual ~Input(void);
907
908 virtual long GetC(void) = 0;
909
910 // return the size if known, -1 if unknown
911 virtual long GetSize(void) const;
912
913 void ResetCounters(long line = 1)
914 {
915 f_page = 1;
916 f_page_line = 1;
917 f_paragraph = 1;
918 f_line = line;
919 }
920
NewPage(void)921 void NewPage(void)
922 {
923 ++f_page;
924 f_page_line = 1;
925 f_paragraph = 1;
926 }
NewParagraph(void)927 void NewParagraph(void)
928 {
929 ++f_paragraph;
930 }
NewLine(void)931 void NewLine(void)
932 {
933 ++f_page_line;
934 ++f_line;
935 }
936
Page(void)937 long Page(void) const
938 {
939 return f_page;
940 }
PageLine(void)941 long PageLine(void) const
942 {
943 return f_page_line;
944 }
Paragraph(void)945 long Paragraph(void) const
946 {
947 return f_paragraph;
948 }
Line(void)949 virtual long Line(void) const
950 {
951 return f_line;
952 }
953
954 private:
955 long f_page;
956 long f_page_line;
957 long f_paragraph;
958 long f_line;
959 };
960
961
962
963
964
965
966
967 class FileInput : public Input
968 {
969 public:
970 FileInput(void);
971 virtual ~FileInput();
972 virtual const char * GetFilename(void) const;
973 bool StandardInput(void);
974 bool Open(const char *filename);
975 void Close(void);
976 virtual long GetC(void);
977 virtual long GetSize(void) const;
978 void SetOriginalFilename(const char *original_filename);
979
980 protected:
981 char * f_filename;
982 char * f_original_filename;
983 FILE * f_file;
984 long f_size;
985 };
986
987
988 class FileUCS32Input : public FileInput
989 {
990 public:
991 virtual long GetC(void);
992 };
993
994
995
996 class StringInput : public Input
997 {
998 public:
999 StringInput(const char *filename = 0);
1000 virtual ~StringInput();
1001
1002 void Set(const long *str, long size, unsigned long line);
1003 long GetSize(void) const;
1004 virtual long GetC(void);
1005
1006 virtual const char * GetFilename(void) const;
1007
1008 private:
1009 int f_pos;
1010 String f_str;
1011 const char * f_filename;
1012 };
1013
1014
1015
1016 // In order to support different types of file systems, the
1017 // compiler supports a file retriever. Any time a file is
1018 // opened, it calls the retriever (if defined) and uses
1019 // that file. If no retriever was defined, the default is
1020 // used: attempt to open the file with fopen() or an equivalent.
1021 // In particular, this is used to handle the internal ASC files.
1022 class InputRetriever
1023 {
1024 public:
~InputRetriever()1025 virtual ~InputRetriever() {}
1026
1027 virtual Input * Retrieve(const char *filename) = 0;
1028 };
1029
1030
1031
1032 // Options you can tweak so the compiler reacts in a different
1033 // manner in different situations (for instance, the \e escape
1034 // sequence can be used to generate the escape character whenever
1035 // the extended escape sequences is set to 1).
1036 enum option_t
1037 {
1038 AS_OPTION_UNKNOWN = 0,
1039 AS_OPTION_DEBUG,
1040 AS_OPTION_DEBUG_LEXER,
1041 AS_OPTION_EXTENDED_ESCAPE_SEQUENCES,
1042 AS_OPTION_EXTENDED_OPERATORS,
1043 AS_OPTION_EXTENDED_STATEMENTS,
1044 AS_OPTION_OCTAL,
1045 AS_OPTION_STRICT,
1046 AS_OPTION_TRACE,
1047 AS_OPTION_TRACE_TO_OBJECT,
1048
1049 AS_OPTION_max
1050 };
1051
1052 class Options
1053 {
1054 public:
Options(void)1055 Options(void)
1056 {
1057 memset(f_options, 0, sizeof(f_options));
1058
1059 // we're always in strict mode
1060 f_options[AS_OPTION_STRICT] = 1;
1061 }
1062
SetOption(option_t option,long value)1063 void SetOption(option_t option, long value)
1064 {
1065 AS_ASSERT(option < AS_OPTION_max);
1066
1067 // we're always in strict mode
1068 if(option == AS_OPTION_STRICT) {
1069 value = 1;
1070 }
1071 f_options[option] = value;
1072 }
GetOption(option_t option)1073 long GetOption(option_t option)
1074 {
1075 AS_ASSERT(option < AS_OPTION_max);
1076
1077 return f_options[option];
1078 }
1079
1080 private:
1081 long f_options[AS_OPTION_max];
1082 };
1083
1084
1085
1086
1087 // The parser class is mostly hidden to you.
1088 // You can't derive from it. You call the CreateParser() to use it.
1089 // Once you are finished with the parser, delete it.
1090 // Note that deleting the parser doesn't delete the nodes and thus
1091 // you can work with the tree even after you deleted the parser.
1092 //
1093 // You use like this:
1094 //
1095 // using namespace sswf::as;
1096 // MyInput input;
1097 // Parser *parser = Parser::CreateParser();
1098 // parser->SetInput(input);
1099 // // it is optional to set the options
1100 // parser->SetOptions(options);
1101 // NodePtr root = parser->Parse();
1102 //
1103 // NOTE: the input and options are NOT copied, a pointer to these
1104 // object is saved in the parser. Delete the Parser() before you
1105 // delete them. Also, this means you can change the options as the
1106 // parsing goes on (i.e. usually this happens in Input::Error().).
1107 class Parser
1108 {
1109 public:
~Parser()1110 virtual ~Parser() {}
1111
1112 static Parser * CreateParser(void);
1113 static const char * Version(void);
1114
1115 virtual void SetInput(Input& input) = 0;
1116 virtual void SetOptions(Options& options) = 0;
1117 virtual NodePtr& Parse(void) = 0;
1118 };
1119
1120
1121 // Once a program was parsed, you need to compile it. This
1122 // mainly means resolving the references (i.e. identifiers)
1123 // which may generate the loading of libraries specified in
1124 // import instructions (note that some import instructions
1125 // are automatic for the global and native environments.)
1126 //
1127 // The code, after you ran the parser looks like this:
1128 //
1129 // Compiler *compiler = Compiler::CreateCompiler();
1130 // // this is the same options as for the parser
1131 // compiler->SetOptions(options);
1132 // error_count = compiler->Compile(root);
1133 //
1134 // The Compile() function returns the number of errors
1135 // encountered while compiling. The root parameter is
1136 // what was returned by the Parse() function of the
1137 // Parser object.
1138 class Compiler
1139 {
1140 public:
~Compiler()1141 virtual ~Compiler() {}
1142
1143 // NOTE: to be thread safe, this call should be
1144 // protected so only one thread can call it at
1145 // a time (or create a compiler before any thread)
1146 static Compiler * CreateCompiler(InputRetriever *retriever);
1147 static const char * Version(void);
1148
1149 virtual InputRetriever *SetInputRetriever(InputRetriever *retriever) = 0;
1150 virtual void SetErrorStream(ErrorStream& error_stream) = 0;
1151 virtual void SetOptions(Options& options) = 0;
1152 virtual int Compile(NodePtr& tree) = 0;
1153 };
1154
1155
1156
1157
1158 // Finally, once the program was parsed and then compiled
1159 // one usually wants to optimize it. This means removing
1160 // all the possible expressions and statements which can
1161 // be removed to make the code more efficient. The
1162 // optimizations applied can be tweaked using the options.
1163 //
1164 // The code, after you ran the compiler looks like this:
1165 //
1166 // Optimizer *optimizer = Optimizer::CreateOptimizer();
1167 // // this is the same options as for the parser
1168 // optimize->SetOptions(options);
1169 // optimize->Optimize(root);
1170 //
1171 // The Optimize() function goes through the list of
1172 // nodes defined in the root parameter and it tries to
1173 // remove all possible expressions and functions which
1174 // will have no effect in the final output (certain things,
1175 // such as x + 0, are not removed since it has an effect!).
1176 // The root parameter is what was returned by the Parse()
1177 // function of the Parser object.
1178 //
1179 // Note that it is expected that you first Compile()
1180 // the nodes, but it is possible to call the optimizer
1181 // without first running any compilation.
1182 class Optimizer
1183 {
1184 public:
~Optimizer()1185 virtual ~Optimizer() {}
1186
1187 static Optimizer * CreateOptimizer(void);
1188 static const char * Version(void);
1189
1190 virtual void SetErrorStream(ErrorStream& error_stream) = 0;
1191 virtual void SetOptions(Options& options) = 0;
1192 virtual int Optimize(NodePtr& tree) = 0;
1193 virtual int GetLastLabel(void) const = 0;
1194 virtual void SetFirstLabel(int label) = 0;
1195 };
1196
1197
1198
1199
1200 // Now you're on your own! You have a perfect tree
1201 // and you can generate valid code from it...
1202 //
1203 // Each node has a Data structure, a set of children
1204 // node and a set of attribute flags (WARNING:
1205 // the attributes are computed by the compiler; you
1206 // need to call Compile() with a compiler to get
1207 // the attributes).
1208
1209
1210
1211
1212 }; // namespace as
1213 }; // namespace sswf
1214 #endif /* #ifndef LIBSSWF_AS_H */
1215