www.pudn.com > sswf-1.7.4-src.zip > libsswf_as.h
/* libsswf_as.h -- written by Alexis WILKE for Made to Order Software, Ltd. (c) 2005-2006 */ #ifndef LIBSSWF_AS_H #define LIBSSWF_AS_H /* Copyright (c) 2005-2006 Made to Order Software, Ltd. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include#include #include #include #ifdef _MSVC #include #include #include #define snprintf _snprintf #define vsnprintf _vsnprintf inline int mkdir(const char *filename) { return _mkdir(filename); } inline int isnan(double nan) { return _isnan(nan); } inline int isinf(double d) { int c; c = _fpclass(d); if(c == _FPCLASS_PINF) { return 1; } else if(c == _FPCLASS_NINF) { return -1; } return 0; } typedef __int64 int64_t; typedef unsigned __int64 uint64_t; typedef __int32 int32_t; typedef unsigned __int32 uint32_t; inline int64_t strtoll(const char *str, char *end, int base) { return _atoi64(str); } #else #include #include #include #endif #include #include #include #include #include "sswf/libsswf-config.h" #ifdef NEED_FP_NAN #ifndef FP_NAN static union __nan_value { uint32_t __l; float __d; } __nan_union = { 0x7fc00000UL }; #define FP_NAN (__nan_union.__d) #endif #endif #ifdef NEED_ISINF #if IRIX // my old version (6.5.7) doesn't have a correct isinf() function // if you have a newer version and you are sure you have a proper // version of isinf(), then feel free to remove this declaration #include static int isinf(double d) { int c; c = fp_class_d(d); if(c == FP_POS_INF) { return 1; } else if(c == FP_NEG_INF) { return -1; } return 0; } #endif #endif namespace sswf { namespace as { #if defined(_DEBUG) || defined(DEBUG) #define AS_ASSERT(test) { if(!(test)) printf("FATAL ERROR: AS_ASSERT(" #test ") is false in " __FILE__ " at line %d.\n", __LINE__), abort(); } #else #define AS_ASSERT(test) #endif enum err_code_t { AS_ERR_NONE = 0, AS_ERR_ABSTRACT, AS_ERR_BAD_PRAGMA, AS_ERR_CANNOT_MATCH, AS_ERR_CANNOT_OVERLOAD, AS_ERR_CANNOT_OVERWRITE_CONST, AS_ERR_CASE_LABEL, AS_ERR_COLON_EXPECTED, AS_ERR_CURVLY_BRAKETS_EXPECTED, AS_ERR_DEFAULT_LABEL, AS_ERR_DIVIDE_BY_ZERO, AS_ERR_DUPLICATES, AS_ERR_DYNAMIC, AS_ERR_FINAL, AS_ERR_IMPORPER_STATEMENT, AS_ERR_INACCESSIBLE_STATEMENT, AS_ERR_INCOMPATIBLE, AS_ERR_INCOMPATIBLE_PRAGMA_ARGUMENT, AS_ERR_INSTANCE_EXPECTED, AS_ERR_INTERNAL_ERROR, AS_ERR_INTRINSIC, AS_ERR_INVALID_ARRAY_FUNCTION, AS_ERR_INVALID_ATTRIBUTES, AS_ERR_INVALID_CATCH, AS_ERR_INVALID_CLASS, AS_ERR_INVALID_CONDITIONAL, AS_ERR_INVALID_DEFINITION, AS_ERR_INVALID_DO, AS_ERR_INVALID_ENUM, AS_ERR_INVALID_EXPRESSION, AS_ERR_INVALID_FIELD, AS_ERR_INVALID_FIELD_NAME, AS_ERR_INVALID_FRAME, AS_ERR_INVALID_FUNCTION, AS_ERR_INVALID_GOTO, AS_ERR_INVALID_KEYWORD, AS_ERR_INVALID_LABEL, AS_ERR_INVALID_NAMESPACE, AS_ERR_INVALID_NODE, AS_ERR_INVALID_OPERATOR, AS_ERR_INVALID_PACKAGE_NAME, AS_ERR_INVALID_PARAMETERS, AS_ERR_INVALID_REST, AS_ERR_INVALID_RETURN_TYPE, AS_ERR_INVALID_SCOPE, AS_ERR_INVALID_TRY, AS_ERR_INVALID_TYPE, AS_ERR_INVALID_UNICODE_ESCAPE_SEQUENCE, AS_ERR_INVALID_VARIABLE, AS_ERR_LABEL_NOT_FOUND, AS_ERR_LOOPING_REFERENCE, AS_ERR_MISMATCH_FUNC_VAR, AS_ERR_NEED_CONST, AS_ERR_NOT_FOUND, AS_ERR_NOT_SUPPORTED, AS_ERR_PARENTHESIS_EXPECTED, AS_ERR_PRAGMA_FAILED, AS_ERR_SEMICOLON_EXPECTED, AS_ERR_SQUARE_BRAKETS_EXPECTED, AS_ERR_STATIC, AS_ERR_UNKNOWN_ESCAPE_SEQUENCE, AS_ERR_UNKNOWN_OPERATOR, AS_ERR_UNTERMINTED_STRING, AS_ERR_UNEXPECTED_PUNCTUATION, AS_ERR_max }; class Node; // the node type is often referenced as a token enum node_t { NODE_EOF = -1, // when reading after the end of the file NODE_UNKNOWN = 0, // node still uninitialized // here are all the punctuation as themselves // (i.e. '<', '>', '=', '+', '-', etc.) NODE_ADD = '+', NODE_BITWISE_AND = '&', NODE_BITWISE_NOT = '~', NODE_ASSIGNMENT = '=', NODE_BITWISE_OR = '|', NODE_BITWISE_XOR = '^', NODE_CLOSE_CURVLY_BRACKET = '}', NODE_CLOSE_PARENTHESIS = ')', NODE_CLOSE_SQUARE_BRACKET = ']', NODE_COLON = ':', NODE_COMMA = ',', NODE_CONDITIONAL = '?', NODE_DIVIDE = '/', NODE_GREATER = '>', NODE_LESS = '<', NODE_LOGICAL_NOT = '!', NODE_MODULO = '%', NODE_MULTIPLY = '*', NODE_OPEN_CURVLY_BRACKET = '{', NODE_OPEN_PARENTHESIS = '(', NODE_OPEN_SQUARE_BRACKET = '[', NODE_MEMBER = '.', NODE_SEMICOLON = ';', NODE_SUBTRACT = '-', // The following are composed tokens // (operators, keywords, strings, numbers...) NODE_other = 1000, NODE_ARRAY, NODE_ARRAY_LITERAL, NODE_AS, NODE_ASSIGNMENT_ADD, NODE_ASSIGNMENT_BITWISE_AND, NODE_ASSIGNMENT_BITWISE_OR, NODE_ASSIGNMENT_BITWISE_XOR, NODE_ASSIGNMENT_DIVIDE, NODE_ASSIGNMENT_LOGICAL_AND, NODE_ASSIGNMENT_LOGICAL_OR, NODE_ASSIGNMENT_LOGICAL_XOR, NODE_ASSIGNMENT_MAXIMUM, NODE_ASSIGNMENT_MINIMUM, NODE_ASSIGNMENT_MODULO, NODE_ASSIGNMENT_MULTIPLY, NODE_ASSIGNMENT_POWER, NODE_ASSIGNMENT_ROTATE_LEFT, NODE_ASSIGNMENT_ROTATE_RIGHT, NODE_ASSIGNMENT_SHIFT_LEFT, NODE_ASSIGNMENT_SHIFT_RIGHT, NODE_ASSIGNMENT_SHIFT_RIGHT_UNSIGNED, NODE_ASSIGNMENT_SUBTRACT, NODE_ATTRIBUTES, NODE_AUTO, NODE_BREAK, NODE_CALL, NODE_CASE, NODE_CATCH, NODE_CLASS, NODE_CONST, NODE_CONTINUE, NODE_DEBUGGER, NODE_DECREMENT, NODE_DEFAULT, NODE_DELETE, NODE_DIRECTIVE_LIST, NODE_DO, NODE_ELSE, NODE_EMPTY, NODE_ENTRY, NODE_ENUM, NODE_EQUAL, NODE_EXCLUDE, NODE_EXTENDS, NODE_FALSE, NODE_FINALLY, NODE_FLOAT64, NODE_FOR, NODE_FOR_IN, NODE_FUNCTION, NODE_GOTO, NODE_GREATER_EQUAL, NODE_IDENTIFIER, NODE_IF, NODE_IMPLEMENTS, NODE_IMPORT, NODE_IN, NODE_INCLUDE, NODE_INCREMENT, NODE_INSTANCEOF, NODE_INT64, NODE_INTERFACE, NODE_IS, NODE_LABEL, NODE_LESS_EQUAL, NODE_LIST, NODE_LOGICAL_AND, NODE_LOGICAL_OR, NODE_LOGICAL_XOR, NODE_MATCH, NODE_MAXIMUM, NODE_MINIMUM, NODE_NAME, NODE_NAMESPACE, NODE_NEW, NODE_NOT_EQUAL, NODE_NULL, NODE_OBJECT_LITERAL, NODE_PACKAGE, NODE_PARAM, NODE_PARAMETERS, NODE_PARAM_MATCH, NODE_POST_DECREMENT, NODE_POST_INCREMENT, NODE_POWER, NODE_PRIVATE, NODE_PROGRAM, NODE_PUBLIC, NODE_RANGE, NODE_REGULAR_EXPRESSION, NODE_REST, NODE_RETURN, NODE_ROOT, NODE_ROTATE_LEFT, NODE_ROTATE_RIGHT, NODE_SCOPE, NODE_SET, NODE_SHIFT_LEFT, NODE_SHIFT_RIGHT, NODE_SHIFT_RIGHT_UNSIGNED, NODE_STRICTLY_EQUAL, NODE_STRICTLY_NOT_EQUAL, NODE_STRING, NODE_SUPER, NODE_SWITCH, NODE_THIS, NODE_THROW, NODE_TRUE, NODE_TRY, NODE_TYPE, NODE_TYPEOF, NODE_UNDEFINED, NODE_USE, NODE_VAR, NODE_VARIABLE, NODE_VAR_ATTRIBUTES, NODE_VIDENTIFIER, NODE_VOID, NODE_WHILE, NODE_WITH, NODE_max, // mark the limit // used to extract the node type from some integers // (used by the SWITCH statement at time of writing) NODE_MASK = 0x0FFFF }; // some nodes use flags as defined below: enum flags_t { // NODE_CATCH NODE_CATCH_FLAG_TYPED = 0x01, // NODE_DIRECTIVE_LIST NODE_DIRECTIVE_LIST_FLAG_NEW_VARIABLES = 0x01, // NODE_FOR NODE_FOR_FLAG_FOREACH = 0x01, // NODE_FUNCTION NODE_FUNCTION_FLAG_GETTER = 0x01, NODE_FUNCTION_FLAG_SETTER = 0x02, NODE_FUNCTION_FLAG_OUT = 0x04, NODE_FUNCTION_FLAG_VOID = 0x08, NODE_FUNCTION_FLAG_NEVER = 0x10, NODE_FUNCTION_FLAG_NOPARAMS = 0x20, NODE_FUNCTION_FLAG_OPERATOR = 0x40, // NODE_IDENTIFIER, NODE_VIDENTIFIER, NODE_STRING NODE_IDENTIFIER_FLAG_WITH = 0x01, NODE_IDENTIFIER_FLAG_TYPED = 0x02, // NODE_IMPORT NODE_IMPORT_FLAG_IMPLEMENTS = 0x01, // NODE_PACKAGE NODE_PACKAGE_FLAG_FOUND_LABELS = 0x01, NODE_PACKAGE_FLAG_REFERENCED = 0x02, // NODE_PARAM_MATCH NODE_PARAM_MATCH_FLAG_UNPROTOTYPED = 0x01, // NODE_PARAMETERS NODE_PARAMETERS_FLAG_CONST = 0x001, NODE_PARAMETERS_FLAG_IN = 0x002, NODE_PARAMETERS_FLAG_OUT = 0x004, NODE_PARAMETERS_FLAG_NAMED = 0x008, NODE_PARAMETERS_FLAG_REST = 0x010, NODE_PARAMETERS_FLAG_UNCHECKED = 0x020, NODE_PARAMETERS_FLAG_UNPROTOTYPED = 0x040, NODE_PARAMETERS_FLAG_REFERENCED = 0x080, // referenced from a parameter or a variable NODE_PARAMETERS_FLAG_PARAMREF = 0x100, // referenced from another parameter NODE_PARAMETERS_FLAG_CATCH = 0x200, // a parameter defined in a catch() // NODE_SWITCH // WARNING: the switch() integer is also used for the operator node type NODE_SWITCH_FLAG_DEFAULT = 0x80000000, // we found a 'default:' label in that switch // NODE_VARIABLE (and NODE_VAR, NODE_PARAM) NODE_VAR_FLAG_CONST = 0x01, NODE_VAR_FLAG_LOCAL = 0x02, NODE_VAR_FLAG_MEMBER = 0x04, NODE_VAR_FLAG_ATTRIBUTES = 0x08, NODE_VAR_FLAG_ENUM = 0x02000000, // there is a NODE_SET and it somehow needs to be copied NODE_VAR_FLAG_COMPILED = 0x04000000, // Expression() was called on the NODE_SET NODE_VAR_FLAG_INUSE = 0x08000000, // this variable was referenced NODE_VAR_FLAG_ATTRS = 0x10000000, // currently being read for attributes (to avoid loops) NODE_VAR_FLAG_DEFINED = 0x20000000, // was already parsed NODE_VAR_FLAG_DEFINING = 0x40000000, // currently defining, can't read NODE_VAR_FLAG_TOADD = 0x80000000, // to be added in the directive list unused_flag // enables commas on all flags... }; // the following is a list of all the possible attributes in our system // (note that the bits may change in the future) // member visibility static const unsigned long NODE_ATTR_PUBLIC = 0x00000001; static const unsigned long NODE_ATTR_PRIVATE = 0x00000002; static const unsigned long NODE_ATTR_PROTECTED = 0x00000004; static const unsigned long NODE_ATTR_INTERNAL = 0x00000008; // function member type static const unsigned long NODE_ATTR_STATIC = 0x00000010; static const unsigned long NODE_ATTR_ABSTRACT = 0x00000020; static const unsigned long NODE_ATTR_VIRTUAL = 0x00000040; static const unsigned long NODE_ATTR_ARRAY = 0x00000080; // function/variable is defined in your system (execution env.) // you won't find a body for these functions; the variables // will likely be read-only static const unsigned long NODE_ATTR_INTRINSIC = 0x00000100; // operator overload (function member) // Contructor -> another way to construct this type of objects static const unsigned long NODE_ATTR_CONSTRUCTOR = 0x00000200; // function & member constrains // CONST is not currently available as an attribute (see flags instead) //static const unsigned long NODE_ATTR_CONST = 0x00001000; static const unsigned long NODE_ATTR_FINAL = 0x00002000; static const unsigned long NODE_ATTR_ENUMERABLE = 0x00004000; // conditional compilation static const unsigned long NODE_ATTR_TRUE = 0x00010000; static const unsigned long NODE_ATTR_FALSE = 0x00020000; static const unsigned long NODE_ATTR_UNUSED = 0x00040000; // if definition is used, error! // class attribute (whether a class can be enlarged at run time) static const unsigned long NODE_ATTR_DYNAMIC = 0x00100000; // switch attributes static const unsigned long NODE_ATTR_FOREACH = 0x01000000; static const unsigned long NODE_ATTR_NOBREAK = 0x02000000; static const unsigned long NODE_ATTR_AUTOBREAK = 0x04000000; // The following is to make sure we never define the attributes more // than once. static const unsigned long NODE_ATTR_DEFINED = 0x80000000; class String { public: String(void); String(const String& string); String(const char *str); ~String(); String& operator = (const String& string); // Assume ISO-8859-1 as input String& operator = (const char *str); bool operator == (const String& string) const; bool operator != (const String& string) const; bool operator == (const char *str) const; bool operator != (const char *str) const; String& operator += (const String& string); // Assume ISO-8859-1 as input String& operator += (const char *str); int Compare(const String& string) const; int Compare(const char *string) const; bool IsEmpty(void) const; void Empty(void); long GetLength(void) const; const long * Get(void) const; // NOT NULL TERMINATED void Set(const long *str, long size); void AppendChar(long c); String& AppendStr(const long *str, long len); int GetUTF8Length(void) const; int ToUTF8(char *mb, size_t& mb_len) const; // -1 on error, 0 otherwise int FromUTF8(const char *mb, size_t mb_len); // -1 on error, 0 otherwise // WARNING: you need to 'delete [] str' of returned pointer char * GetUTF8(void) const; private: long f_len; long f_max; long * f_str; }; class Int64 { public: Int64(void) { f_int = 0; } Int64(const Int64& src_int) { f_int = src_int.f_int; } Int64& operator = (const Int64& src_int) { f_int = src_int.f_int; return *this; } int64_t Get(void) const { return f_int; } void Set(int64_t new_int) { f_int = new_int; } private: int64_t f_int; }; class Float64 { public: Float64(void) { f_float = 0; } Float64(const Float64& src_float) { f_float = src_float.f_float; } Float64& operator = (const Float64& src_float) { f_float = src_float.f_float; return *this; } double Get(void) const { return f_float; } void Set(double new_float) { f_float = new_float; } private: double f_float; }; class UserData { public: UserData(void) { f_size = 0; f_data = 0; } UserData(const UserData& src) { if(src.f_size > 0) { f_data = 0; New(src.f_size); memcpy(f_data, src.f_data, sizeof(int) * f_size); } else { f_size = 0; f_data = 0; } } ~UserData() { delete [] f_data; } UserData& operator = (const UserData& src) { delete [] f_data; if(src.f_size > 0) { f_data = 0; New(src.f_size); memcpy(f_data, src.f_data, sizeof(int) * f_size); } else { f_size = 0; f_data = 0; } return *this; } void New(int size) { AS_ASSERT(size >= 0); delete [] f_data; if(size > 0) { f_data = new int[size]; // by default we clear it memset(f_data, 0, sizeof(int) * size); } else { f_data = 0; } f_size = size; } int Size(void) const { return f_size; } int * Buffer(void) { // we want to make sure that each call // to Buffer doesn't require this test AS_ASSERT(f_data != 0); return f_data; } const int * Buffer(void) const { // we want to make sure that each call // to Buffer doesn't require this test AS_ASSERT(f_data != 0); return f_data; } private: int f_size; int * f_data; }; struct Data { Data(void) { f_type = NODE_UNKNOWN; } void Clear(void) { f_type = NODE_UNKNOWN; f_int.Set(0); f_float.Set(0.0); f_str.Empty(); } void Display(FILE *out) const; const char * GetTypeName(void) const; // basic conversions bool ToBoolean(void); bool ToNumber(void); bool ToString(void); node_t f_type; Int64 f_int; Float64 f_float; String f_str; UserData f_user_data; }; class Input; class NodePtr { public: enum link_t { LINK_INSTANCE = 0, LINK_TYPE, LINK_ATTRIBUTES, // this is the list of identifiers LINK_max, LINK_GOTO_EXIT = LINK_INSTANCE, LINK_GOTO_ENTER = LINK_TYPE, LINK_end }; NodePtr(void) { f_node = 0; } NodePtr(const NodePtr& node); ~NodePtr(); NodePtr& operator = (const NodePtr& node); void SetInputInfo(const Input *input); void CopyInputInfo(const NodePtr& node); long GetPage(void) const; long GetPageLine(void) const; long GetParagraph(void) const; long GetLine(void) const; const String& GetFilename(void) const; void SetNode(const Node *node); void SetNode(const NodePtr& node); void CreateNode(node_t type = NODE_UNKNOWN); NodePtr& Clone(const NodePtr& source); void ClearNode(void); bool HasNode(void) const { return f_node != 0; } bool SameAs(const NodePtr& node) const { return f_node == node.f_node; } Data& GetData(void) const; void SetData(const Data& data); unsigned long GetAttrs(void) const; // see NODE_ATTR_... void SetAttrs(unsigned long attrs); bool HasSideEffects(void) const; bool IsLocked(void) const; void Lock(void); void Unlock(void); void SetOffset(int offset); int GetOffset(void) const; void ReplaceWith(NodePtr& new_node); void DeleteChild(int index); void AddChild(NodePtr& child); void InsertChild(int idx, NodePtr& child); void SetChild(int index, NodePtr& child); int GetChildCount(void) const; NodePtr& GetChild(int index) const; void SetParent(Node *parent); NodePtr& GetParent(void); void SetLink(link_t index, NodePtr& link); NodePtr& GetLink(link_t index); void AddVariable(NodePtr& variable); int GetVariableCount(void) const; NodePtr& GetVariable(int index) const; void AddLabel(NodePtr& label); int GetLabelCount(void) const; NodePtr& GetLabel(int index) const; NodePtr& FindLabel(const String& name) const; void Display(FILE *out, int indent = 0, NodePtr *parent = 0, char c = '-') const; void DisplayPtr(FILE *out) const; const char * OperatorToString(void); node_t StringToOperator(void); private: Node * f_node; }; class NodeLock { public: NodeLock(NodePtr& node) { f_node = node; if(f_node.HasNode()) { f_node.Lock(); } } ~NodeLock() { if(f_node.HasNode()) { f_node.Unlock(); } } // premature unlocking void Unlock(void) { if(f_node.HasNode()) { f_node.Unlock(); f_node.ClearNode(); } } private: NodePtr f_node; }; // ErrorStream handling object; you can derive from this // class to redirect the errors to a different // output (by default it goes to stderr). // For that purpose, overload the Error() function. // Within your function, use the IntGetFilename() // and IntLine() functions to get the filename // and line where the error occured. // // NOTE: The Input class derives from this class // so it can handle the errors at once. class ErrorStream { public: ErrorStream(void); virtual ~ErrorStream(); // by default, write in stderr; overload to send errors in // your console, etc. virtual void Error(err_code_t err_code, const char *message); // We call one of these functions which transform their // parameters (format + params) in a single easy to use // string sent to Error(). // You don't overload these functions. void ErrMsg(err_code_t err_code, const char *format, ...); void ErrMsg(err_code_t err_code, const char *format, va_list ap); // the following replaces String pointers by their UTF-8 const char * // whenever the format includes a %S -- this makes it work on all // systems without jungling with wide characters too much // also, we support %N for nodes in which case we print out the // filename and line of the given node void ErrStrMsg(err_code_t err_code, const char *format, ...); void ErrStrMsg(err_code_t err_code, const char *format, va_list ap); // errors which should use the node information for the // filename & line number (instead of GetFilename() and Line()) void ErrMsg(err_code_t err_code, const NodePtr& node, const char *format, ...); void ErrStrMsg(err_code_t err_code, const NodePtr& node, const char *format, ...); long ErrCount(void) const { return f_errcnt; } virtual const char * GetFilename(void) const; virtual long Line(void) const; protected: const String& IntGetFilename(void) const; long IntLine(void) const; private: long f_errcnt; NodePtr f_node; mutable String f_filename; // IntGetFilename() must return a string... }; // I/O interface that YOU have to derive from so the // parser can read the input data from somewhere // You need to implement the GetC() function. You can // also overload the Error() function so it prints // the errors in a console of your choice. // The GetFilename() is used by the default Error() // function. It is used to generate an error like gcc. // That function returns "asc" by default. // // Two examples are available below. One reads a USC-4 // formatted file and the other reads a string. class Input : public ErrorStream { public: enum { AS_EOF = -1 }; Input(void); virtual ~Input(void); virtual long GetC(void) = 0; void ResetCounters(long line = 1) { f_page = 1; f_page_line = 1; f_paragraph = 1; f_line = line; } void NewPage(void) { ++f_page; f_page_line = 1; f_paragraph = 1; } void NewParagraph(void) { ++f_paragraph; } void NewLine(void) { ++f_page_line; ++f_line; } long Page(void) const { return f_page; } long PageLine(void) const { return f_page_line; } long Paragraph(void) const { return f_paragraph; } virtual long Line(void) const { return f_line; } private: long f_page; long f_page_line; long f_paragraph; long f_line; }; class FileInput : public Input { public: FileInput(void); virtual ~FileInput(); virtual const char * GetFilename(void) const; bool StandardInput(void); bool Open(const char *filename); void Close(void); virtual long GetC(void); void SetOriginalFilename(const char *original_filename); protected: char * f_filename; char * f_original_filename; FILE * f_file; }; class FileUCS32Input : public FileInput { public: virtual long GetC(void); }; // Feel free to derive from this class if you want to // return a filename to the GetFilename() function. class StringInput : public Input { public: StringInput(void); virtual ~StringInput(); void Set(const long *str, long size, unsigned long line); virtual long GetC(void); private: int f_pos; String f_str; }; // Options you can tweak so the compiler reacts in a different // manner in different situations (for instance, the \e escape // sequence can be used to generate the escape character whenever // the extended escape sequences is set to 1). enum option_t { AS_OPTION_UNKNOWN = 0, AS_OPTION_DEBUG, AS_OPTION_DEBUG_LEXER, AS_OPTION_EXTENDED_ESCAPE_SEQUENCES, AS_OPTION_EXTENDED_OPERATORS, AS_OPTION_EXTENDED_STATEMENTS, AS_OPTION_OCTAL, AS_OPTION_STRICT, AS_OPTION_TRACE, AS_OPTION_TRACE_TO_OBJECT, AS_OPTION_max }; class Options { public: Options(void) { memset(f_options, 0, sizeof(f_options)); // we're always in strict mode f_options[AS_OPTION_STRICT] = 1; } void SetOption(option_t option, long value) { AS_ASSERT(option < AS_OPTION_max); // we're always in strict mode if(option == AS_OPTION_STRICT) { value = 1; } f_options[option] = value; } long GetOption(option_t option) { AS_ASSERT(option < AS_OPTION_max); return f_options[option]; } private: long f_options[AS_OPTION_max]; }; // The parser class is mostly hidden to you. // You can't derive from it. You call the CreateParser() to use it. // Once you are finished with the parser, delete it. // Note that deleting the parser doesn't delete the nodes and thus // you can work with the tree even after you deleted the parser. // // You use like this: // // using namespace sswf::as; // MyInput input; // Parser *parser = Parser::CreateParser(); // parser->SetInput(input); // // it is optional to set the options // parser->SetOptions(options); // NodePtr root = parser->Parse(); // // NOTE: the input and options are NOT copied, a pointer to these // object is saved in the parser. Delete the Parser() before you // delete them. Also, this means you can change the options as the // parsing goes on (i.e. usually this happens in Input::Error().). class Parser { public: static Parser * CreateParser(void); static const char * Version(void); virtual void SetInput(Input& input) = 0; virtual void SetOptions(Options& options) = 0; virtual NodePtr& Parse(void) = 0; }; // Once a program was parsed, you need to compile it. This // mainly means resolving the references (i.e. identifiers) // which may generate the loading of libraries specified in // import instructions (note that some import instructions // are automatic for the global and native environments.) // // The code, after you ran the parser looks like this: // // Compiler *compiler = Compiler::CreateCompiler(); // // this is the same options as for the parser // compiler->SetOptions(options); // error_count = compiler->Compile(root); // // The Compile() function returns the number of errors // encountered while compiling. The root parameter is // what was returned by the Parse() function of the // Parser object. class Compiler { public: // NOTE: to be thread safe, this call should be // protected so only one thread can call it at // a time (or create a compiler before any thread) static Compiler * CreateCompiler(void); static const char * Version(void); virtual void SetErrorStream(ErrorStream& error_stream) = 0; virtual void SetOptions(Options& options) = 0; virtual int Compile(NodePtr& tree) = 0; }; // Finally, once the program was parsed and then compiled // one usually wants to optimize it. This means removing // all the possible expressions and statements which can // be removed to make the code more efficient. The // optimizations applied can be tweaked using the options. // // The code, after you ran the compiler looks like this: // // Optimizer *optimizer = Optimizer::CreateOptimizer(); // // this is the same options as for the parser // optimize->SetOptions(options); // optimize->Optimize(root); // // The Optimize() function goes through the list of // nodes defined in the root parameter and it tries to // remove all possible expressions and functions which // will have no effect in the final output (certain things, // such as x + 0, are not removed since it has an effect!). // The root parameter is what was returned by the Parse() // function of the Parser object. // // Note that it is expected that you first Compile() // the nodes, but it is possible to call the optimizer // without first running any compilation. class Optimizer { public: static Optimizer * CreateOptimizer(void); static const char * Version(void); virtual void SetErrorStream(ErrorStream& error_stream) = 0; virtual void SetOptions(Options& options) = 0; virtual int Optimize(NodePtr& tree) = 0; virtual int GetLastLabel(void) const = 0; virtual void SetFirstLabel(int label) = 0; }; // Now you're on your own! You have a perfect tree // and you can generate valid code from it... // // Each node has a Data structure, a set of children // node and a set of attribute flags (WARNING: // the attributes are computed by the compiler; you // need to call Compile() with a compiler to get // the attributes). }; // namespace as }; // namespace sswf #endif /* #ifndef LIBSSWF_AS_H */