From 2008bdeef102dc18880d59526b2cbdaed9c63a4a Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Mon, 20 Jun 2011 09:31:23 +0000 Subject: [PATCH] started working on parser --- qse/lib/stx/Makefile.am | 2 +- qse/lib/stx/Makefile.in | 5 +- qse/lib/stx/boot.h | 4 +- qse/lib/stx/bootstrp.c | 680 ---------------- qse/lib/stx/bootstrp.h | 21 - qse/lib/stx/name.c | 146 ---- qse/lib/stx/name.h | 39 - qse/lib/stx/par.c | 1616 +++++++++++++++++++++++++++++++++++++++ qse/lib/stx/par.h | 107 +++ qse/lib/stx/stx.h | 1 + 10 files changed, 1730 insertions(+), 891 deletions(-) delete mode 100644 qse/lib/stx/bootstrp.c delete mode 100644 qse/lib/stx/bootstrp.h delete mode 100644 qse/lib/stx/name.c delete mode 100644 qse/lib/stx/name.h create mode 100644 qse/lib/stx/par.c create mode 100644 qse/lib/stx/par.h diff --git a/qse/lib/stx/Makefile.am b/qse/lib/stx/Makefile.am index 4378dc0f..e68630b7 100644 --- a/qse/lib/stx/Makefile.am +++ b/qse/lib/stx/Makefile.am @@ -8,6 +8,6 @@ AM_CPPFLAGS = \ lib_LTLIBRARIES = libqsestx.la -libqsestx_la_SOURCES = stx.c err.c hash.c mem.c obj.c sym.c dic.c cls.c boot.c +libqsestx_la_SOURCES = stx.c err.c hash.c mem.c obj.c sym.c dic.c cls.c boot.c par.c libqsestx_la_LDFLAGS = -L../cmn -L$(libdir) -version-info 1:0:0 -no-undefined libqsestx_la_LIBADD = -lqsecmn diff --git a/qse/lib/stx/Makefile.in b/qse/lib/stx/Makefile.in index f1efcdc2..7769f9e0 100644 --- a/qse/lib/stx/Makefile.in +++ b/qse/lib/stx/Makefile.in @@ -72,7 +72,7 @@ am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libqsestx_la_DEPENDENCIES = am_libqsestx_la_OBJECTS = stx.lo err.lo hash.lo mem.lo obj.lo sym.lo \ - dic.lo cls.lo boot.lo + dic.lo cls.lo boot.lo par.lo libqsestx_la_OBJECTS = $(am_libqsestx_la_OBJECTS) libqsestx_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ @@ -239,7 +239,7 @@ AM_CPPFLAGS = \ -I$(includedir) lib_LTLIBRARIES = libqsestx.la -libqsestx_la_SOURCES = stx.c err.c hash.c mem.c obj.c sym.c dic.c cls.c boot.c +libqsestx_la_SOURCES = stx.c err.c hash.c mem.c obj.c sym.c dic.c cls.c boot.c par.c libqsestx_la_LDFLAGS = -L../cmn -L$(libdir) -version-info 1:0:0 -no-undefined libqsestx_la_LIBADD = -lqsecmn all: all-am @@ -323,6 +323,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/obj.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/par.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stx.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sym.Plo@am__quote@ diff --git a/qse/lib/stx/boot.h b/qse/lib/stx/boot.h index b57dc236..93b585c3 100644 --- a/qse/lib/stx/boot.h +++ b/qse/lib/stx/boot.h @@ -1,5 +1,5 @@ /* - * $Id: symbol.h 118 2008-03-03 11:21:33Z baconevi $ + * $Id$ */ #ifndef _QSE_LIB_STX_BOOT_H_ @@ -13,8 +13,8 @@ int qse_stx_boot ( qse_stx_t* stx ); - qse_word_t qse_stx_findclass (qse_stx_t* stx, const qse_char_t* name); + #ifdef __cplusplus } #endif diff --git a/qse/lib/stx/bootstrp.c b/qse/lib/stx/bootstrp.c deleted file mode 100644 index 8f83ff12..00000000 --- a/qse/lib/stx/bootstrp.c +++ /dev/null @@ -1,680 +0,0 @@ -/* - * $Id: bootstrp.c 118 2008-03-03 11:21:33Z baconevi $ - */ - -#include -#include -#include -#include -#include -#include - -static void __create_bootstrapping_objects (qse_stx_t* stx); -static void __create_builtin_classes (qse_stx_t* stx); -static qse_word_t __make_classvar_dict ( - qse_stx_t* stx, qse_word_t class, const qse_char_t* names); -static void __filein_kernel (qse_stx_t* stx); - -static qse_word_t __count_names (const qse_char_t* str); -static void __set_names ( - qse_stx_t* stx, qse_word_t* array, const qse_char_t* str); - -static qse_word_t __count_subclasses (const qse_char_t* str); -static void __set_subclasses ( - qse_stx_t* stx, qse_word_t* array, const qse_char_t* str); -static void __set_metaclass_subclasses ( - qse_stx_t* stx, qse_word_t* array, const qse_char_t* str); - -struct class_info_t -{ - const qse_char_t* name; - const qse_char_t* superclass; - const qse_char_t* instance_variables; - const qse_char_t* class_variables; - const qse_char_t* pool_dictionaries; - const int indexable; -}; - -typedef struct class_info_t class_info_t; - -static class_info_t class_info[] = -{ - { - QSE_T("Object"), - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_NOT_INDEXABLE - }, - { - QSE_T("UndefinedObject"), - QSE_T("Object"), - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_NOT_INDEXABLE - }, - { - QSE_T("Behavior"), - QSE_T("Object"), - QSE_T("spec methods superclass"), - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_NOT_INDEXABLE - }, - { - QSE_T("Class"), - QSE_T("Behavior"), - QSE_T("name variables classVariables poolDictionaries"), - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_NOT_INDEXABLE - }, - { - QSE_T("Metaclass"), - QSE_T("Behavior"), - QSE_T("instanceClass"), - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_NOT_INDEXABLE - }, - { - QSE_T("Block"), - QSE_T("Object"), - QSE_T("context argCount argLoc bytePointer"), - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_NOT_INDEXABLE - }, - { - QSE_T("Boolean"), - QSE_T("Object"), - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_NOT_INDEXABLE - }, - { - QSE_T("True"), - QSE_T("Boolean"), - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_NOT_INDEXABLE - }, - { - QSE_T("False"), - QSE_T("Boolean"), - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_NOT_INDEXABLE - }, - { - QSE_T("Context"), - QSE_T("Object"), - QSE_T("stack stackTop receiver pc method"), - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_NOT_INDEXABLE - }, - { - QSE_T("Method"), - QSE_T("Object"), - QSE_T("text selector bytecodes tmpCount argCount"), - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_WORD_INDEXABLE - }, - { - QSE_T("Magnitude"), - QSE_T("Object"), - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_NOT_INDEXABLE - }, - { - QSE_T("Association"), - QSE_T("Magnitude"), - QSE_T("key value"), - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_NOT_INDEXABLE - }, - { - QSE_T("Character"), - QSE_T("Magnitude"), - QSE_T("value"), - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_NOT_INDEXABLE - }, - { - QSE_T("Number"), - QSE_T("Magnitude"), - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_NOT_INDEXABLE - }, - { - QSE_T("Integer"), - QSE_T("Number"), - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_NOT_INDEXABLE - }, - { - QSE_T("SmallInteger"), - QSE_T("Integer"), - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_NOT_INDEXABLE - }, - { - QSE_T("LargeInteger"), - QSE_T("Integer"), - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_BYTE_INDEXABLE - }, - { - QSE_T("Collection"), - QSE_T("Magnitude"), - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_NOT_INDEXABLE - }, - { - QSE_T("IndexedCollection"), - QSE_T("Collection"), - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_NOT_INDEXABLE - }, - { - QSE_T("Array"), - QSE_T("IndexedCollection"), - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_WORD_INDEXABLE - }, - { - QSE_T("ByteArray"), - QSE_T("IndexedCollection"), - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_BYTE_INDEXABLE - }, - { - QSE_T("Dictionary"), - QSE_T("IndexedCollection"), - QSE_T("tally"), - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_WORD_INDEXABLE - }, - { - QSE_T("SystemDictionary"), - QSE_T("Dictionary"), - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_WORD_INDEXABLE - }, - { - QSE_T("PoolDictionary"), - QSE_T("Dictionary"), - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_WORD_INDEXABLE - }, - { - QSE_T("String"), - QSE_T("IndexedCollection"), - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_CHAR_INDEXABLE - }, - { - QSE_T("Symbol"), - QSE_T("String"), - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_CHAR_INDEXABLE - }, - { - QSE_T("Link"), - QSE_T("Object"), - QSE_T("link"), - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_NOT_INDEXABLE - }, - { - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_NULL, - QSE_STX_SPEC_NOT_INDEXABLE - } -}; - -qse_word_t INLINE __new_string (qse_stx_t* stx, const qse_char_t* str) -{ - qse_word_t x; - - qse_assert (stx->class_string != stx->nil); - x = qse_stx_alloc_char_object (stx, str); - QSE_STX_CLASS(stx,x) = stx->class_string; - - return x; -} - -int qse_stx_bootstrap (qse_stx_t* stx) -{ - qse_word_t symbol_Smalltalk; - qse_word_t object_meta; - - __create_bootstrapping_objects (stx); - - /* object, class, and array are precreated for easier instantiation - * of builtin classes */ - stx->class_object = qse_stx_new_class (stx, QSE_T("Object")); - stx->class_class = qse_stx_new_class (stx, QSE_T("Class")); - stx->class_array = qse_stx_new_class (stx, QSE_T("Array")); - stx->class_bytearray = qse_stx_new_class (stx, QSE_T("ByteArray")); - stx->class_string = qse_stx_new_class (stx, QSE_T("String")); - stx->class_character = qse_stx_new_class (stx, QSE_T("Character")); - stx->class_context = qse_stx_new_class (stx, QSE_T("Context")); - stx->class_system_dictionary = - qse_stx_new_class (stx, QSE_T("SystemDictionary")); - stx->class_method = - qse_stx_new_class (stx, QSE_T("Method")); - stx->class_smallinteger = - qse_stx_new_class (stx, QSE_T("SmallInteger")); - - __create_builtin_classes (stx); - - /* (Object class) setSuperclass: Class */ - object_meta = QSE_STX_CLASS(stx,stx->class_object); - QSE_STX_WORD_AT(stx,object_meta,QSE_STX_METACLASS_SUPERCLASS) = stx->class_class; - /* instance class for Object is set here as it is not - * set in __create_builtin_classes */ - QSE_STX_WORD_AT(stx,object_meta,QSE_STX_METACLASS_INSTANCE_CLASS) = stx->class_object; - - /* for some fun here */ - { - qse_word_t array; - array = qse_stx_new_array (stx, 1); - QSE_STX_WORD_AT(stx,array,0) = object_meta; - QSE_STX_WORD_AT(stx,stx->class_class,QSE_STX_CLASS_SUBCLASSES) = array; - } - - /* more initialization */ - QSE_STX_CLASS(stx,stx->smalltalk) = stx->class_system_dictionary; - - symbol_Smalltalk = qse_stx_new_symbol (stx, QSE_T("Smalltalk")); - qse_stx_dict_put (stx, stx->smalltalk, symbol_Smalltalk, stx->smalltalk); - - /* create #nil, #true, #false */ - qse_stx_new_symbol (stx, QSE_T("nil")); - qse_stx_new_symbol (stx, QSE_T("true")); - qse_stx_new_symbol (stx, QSE_T("false")); - - /* nil setClass: UndefinedObject */ - QSE_STX_CLASS(stx,stx->nil) = - qse_stx_lookup_class(stx, QSE_T("UndefinedObject")); - /* true setClass: True */ - QSE_STX_CLASS(stx,stx->true) = - qse_stx_lookup_class (stx, QSE_T("True")); - /* fales setClass: False */ - QSE_STX_CLASS(stx,stx->false) = - qse_stx_lookup_class (stx, QSE_T("False")); - - __filein_kernel (stx); - return 0; -} - -static void __create_bootstrapping_objects (qse_stx_t* stx) -{ - qse_word_t class_SymbolMeta; - qse_word_t class_MetaclassMeta; - qse_word_t class_AssociationMeta; - qse_word_t symbol_Symbol; - qse_word_t symbol_Metaclass; - qse_word_t symbol_Association; - - /* allocate three keyword objects */ - stx->ref.nil = qse_stx_alloc_word_object (stx, QSE_NULL, 0, QSE_NULL, 0); - stx->ref.true = qse_stx_alloc_word_object (stx, QSE_NULL, 0, QSE_NULL, 0); - stx->ref.false = qse_stx_alloc_word_object (stx, QSE_NULL, 0, QSE_NULL, 0); - - QSE_ASSERT (stx->ref.nil == QSE_STX_NIL); - QSE_ASSERT (stx->ref.true == QSE_STX_TRUE); - QSE_ASSERT (stx->ref.false == QSE_STX_FALSE); - - stx->symtab = qse_stx_alloc_word_object ( - stx, QSE_NULL, 1, QSE_NULL, 256); - QSE_STX_WORDAT(stx,stx->symtab,QSE_STX_SYMSET_TALLY) = QSE_STX_INTTOREF(0); - - /* system dictionary */ - /* TODO: dictionary size */ - stx->smalltalk = qse_stx_alloc_word_object ( - stx, QSE_NULL, 1, QSE_NULL, 256); - /* set tally */ - QSE_STX_WORD_AT(stx,stx->smalltalk,0) = QSE_STX_TO_SMALLINT(0); - - /* Symbol */ - stx->class_symbol = qse_stx_alloc_word_object( - stx, QSE_NULL, QSE_STX_CLASS_SIZE, QSE_NULL, 0); - /* Metaclass */ - stx->class_metaclass = qse_stx_alloc_word_object( - stx, QSE_NULL, QSE_STX_CLASS_SIZE, QSE_NULL, 0); - /* Association */ - stx->class_association = qse_stx_alloc_word_object( - stx, QSE_NULL, QSE_STX_CLASS_SIZE, QSE_NULL, 0); - - /* Metaclass is a class so it has the same structure - * as a normal class. "Metaclass class" is an instance of - * Metaclass. */ - - /* Symbol class */ - class_SymbolMeta = qse_stx_alloc_word_object( - stx, QSE_NULL, QSE_STX_METACLASS_SIZE, QSE_NULL, 0); - /* Metaclass class */ - class_MetaclassMeta = qse_stx_alloc_word_object( - stx, QSE_NULL, QSE_STX_METACLASS_SIZE, QSE_NULL, 0); - /* Association class */ - class_AssociationMeta = qse_stx_alloc_word_object( - stx, QSE_NULL, QSE_STX_METACLASS_SIZE, QSE_NULL, 0); - - /* (Symbol class) setClass: Metaclass */ - QSE_STX_CLASS(stx,class_SymbolMeta) = stx->class_metaclass; - /* (Metaclass class) setClass: Metaclass */ - QSE_STX_CLASS(stx,class_MetaclassMeta) = stx->class_metaclass; - /* (Association class) setClass: Metaclass */ - QSE_STX_CLASS(stx,class_AssociationMeta) = stx->class_metaclass; - - /* Symbol setClass: (Symbol class) */ - QSE_STX_CLASS(stx,stx->class_symbol) = class_SymbolMeta; - /* Metaclass setClass: (Metaclass class) */ - QSE_STX_CLASS(stx,stx->class_metaclass) = class_MetaclassMeta; - /* Association setClass: (Association class) */ - QSE_STX_CLASS(stx,stx->class_association) = class_AssociationMeta; - - /* (Symbol class) setSpec: CLASS_SIZE */ - QSE_STX_WORD_AT(stx,class_SymbolMeta,QSE_STX_CLASS_SPEC) = - QSE_STX_TO_SMALLINT((QSE_STX_CLASS_SIZE << QSE_STX_SPEC_INDEXABLE_BITS) | QSE_STX_SPEC_NOT_INDEXABLE); - /* (Metaclass class) setSpec: CLASS_SIZE */ - QSE_STX_WORD_AT(stx,class_MetaclassMeta,QSE_STX_CLASS_SPEC) = - QSE_STX_TO_SMALLINT((QSE_STX_CLASS_SIZE << QSE_STX_SPEC_INDEXABLE_BITS) | QSE_STX_SPEC_NOT_INDEXABLE); - /* (Association class) setSpec: CLASS_SIZE */ - QSE_STX_WORD_AT(stx,class_AssociationMeta,QSE_STX_CLASS_SPEC) = - QSE_STX_TO_SMALLINT((QSE_STX_CLASS_SIZE << QSE_STX_SPEC_INDEXABLE_BITS) | QSE_STX_SPEC_NOT_INDEXABLE); - - /* specs for class_metaclass, class_association, - * class_symbol are set later in __create_builtin_classes */ - - /* #Symbol */ - symbol_Symbol = qse_stx_new_symbol (stx, QSE_T("Symbol")); - /* #Metaclass */ - symbol_Metaclass = qse_stx_new_symbol (stx, QSE_T("Metaclass")); - /* #Association */ - symbol_Association = qse_stx_new_symbol (stx, QSE_T("Association")); - - /* Symbol setName: #Symbol */ - QSE_STX_WORD_AT(stx,stx->class_symbol,QSE_STX_CLASS_NAME) = symbol_Symbol; - /* Metaclass setName: #Metaclass */ - QSE_STX_WORD_AT(stx,stx->class_metaclass,QSE_STX_CLASS_NAME) = symbol_Metaclass; - /* Association setName: #Association */ - QSE_STX_WORD_AT(stx,stx->class_association,QSE_STX_CLASS_NAME) = symbol_Association; - - /* register class names into the system dictionary */ - qse_stx_dict_put (stx, - stx->smalltalk, symbol_Symbol, stx->class_symbol); - qse_stx_dict_put (stx, - stx->smalltalk, symbol_Metaclass, stx->class_metaclass); - qse_stx_dict_put (stx, - stx->smalltalk, symbol_Association, stx->class_association); -} - -static void __create_builtin_classes (qse_stx_t* stx) -{ - class_info_t* p; - qse_word_t class, superclass, array; - qse_stx_class_t* class_obj, * superclass_obj; - qse_word_t metaclass; - qse_stx_metaclass_t* metaclass_obj; - qse_word_t n, nfields; - - qse_assert (stx->class_array != stx->nil); - - for (p = class_info; p->name != QSE_NULL; p++) { - class = qse_stx_lookup_class(stx, p->name); - if (class == stx->nil) { - class = qse_stx_new_class (stx, p->name); - } - - qse_assert (class != stx->nil); - class_obj = (qse_stx_class_t*)QSE_STX_OBJPTR(stx, class); - class_obj->superclass = (p->superclass == QSE_NULL)? - stx->nil: qse_stx_lookup_class(stx,p->superclass); - - nfields = 0; - if (p->superclass != QSE_NULL) { - qse_word_t meta; - qse_stx_metaclass_t* meta_obj; - - superclass = qse_stx_lookup_class(stx,p->superclass); - qse_assert (superclass != stx->nil); - - meta = class_obj->header.class; - meta_obj = (qse_stx_metaclass_t*)QSE_STX_OBJPTR(stx,meta); - meta_obj->superclass = QSE_STX_CLASS(stx,superclass); - meta_obj->instance_class = class; - - while (superclass != stx->nil) { - superclass_obj = (qse_stx_class_t*) - QSE_STX_OBJPTR(stx,superclass); - nfields += - QSE_STX_FROMSMALLINT(superclass_obj->spec) >> - QSE_STX_SPEC_INDEXABLE_BITS; - superclass = superclass_obj->superclass; - } - - } - - if (p->instance_variables != QSE_NULL) { - nfields += __count_names (p->instance_variables); - class_obj->variables = - __new_string (stx, p->instance_variables); - } - - qse_assert (nfields <= 0 || (nfields > 0 && - (p->indexable == QSE_STX_SPEC_NOT_INDEXABLE || - p->indexable == QSE_STX_SPEC_WORD_INDEXABLE))); - - class_obj->spec = QSE_STX_TO_SMALLINT( - (nfields << QSE_STX_SPEC_INDEXABLE_BITS) | p->indexable); - } - - for (p = class_info; p->name != QSE_NULL; p++) { - class = qse_stx_lookup_class(stx, p->name); - qse_assert (class != stx->nil); - - class_obj = (qse_stx_class_t*)QSE_STX_OBJPTR(stx, class); - - if (p->class_variables != QSE_NULL) { - class_obj->class_variables = - __make_classvar_dict(stx, class, p->class_variables); - } - - /* - TODO: - if (p->pool_dictionaries != QSE_NULL) { - class_obj->pool_dictionaries = - __make_pool_dictionary(stx, class, p->pool_dictionaries); - } - */ - } - - /* fill subclasses */ - for (p = class_info; p->name != QSE_NULL; p++) { - n = __count_subclasses (p->name); - array = qse_stx_new_array (stx, n); - __set_subclasses (stx, QSE_STX_DATA(stx,array), p->name); - - class = qse_stx_lookup_class(stx, p->name); - qse_assert (class != stx->nil); - class_obj = (qse_stx_class_t*)QSE_STX_OBJPTR(stx, class); - class_obj->subclasses = array; - } - - /* fill subclasses for metaclasses */ - for (p = class_info; p->name != QSE_NULL; p++) { - n = __count_subclasses (p->name); - array = qse_stx_new_array (stx, n); - __set_metaclass_subclasses (stx, QSE_STX_DATA(stx,array), p->name); - - class = qse_stx_lookup_class(stx, p->name); - qse_assert (class != stx->nil); - metaclass = QSE_STX_CLASS(stx,class); - metaclass_obj = (qse_stx_metaclass_t*)QSE_STX_OBJPTR(stx, metaclass); - metaclass_obj->subclasses = array; - } -} - -static qse_word_t __count_names (const qse_char_t* str) -{ - qse_word_t n = 0; - const qse_char_t* p = str; - - do { - while (*p == QSE_T(' ') || - *p == QSE_T('\t')) p++; - if (*p == QSE_T('\0')) break; - - n++; - while (*p != QSE_T(' ') && - *p != QSE_T('\t') && - *p != QSE_T('\0')) p++; - } while (1); - - return n; -} - -static void __set_names ( - qse_stx_t* stx, qse_word_t* array, const qse_char_t* str) -{ - qse_word_t n = 0; - const qse_char_t* p = str; - const qse_char_t* name; - - do { - while (*p == QSE_T(' ') || - *p == QSE_T('\t')) p++; - if (*p == QSE_T('\0')) break; - - name = p; - while (*p != QSE_T(' ') && - *p != QSE_T('\t') && - *p != QSE_T('\0')) p++; - - array[n++] = qse_stx_new_symbolx (stx, name, p - name); - } while (1); -} - -static qse_word_t __count_subclasses (const qse_char_t* str) -{ - class_info_t* p; - qse_word_t n = 0; - - for (p = class_info; p->name != QSE_NULL; p++) { - if (p->superclass == QSE_NULL) continue; - if (qse_strcmp (str, p->superclass) == 0) n++; - } - - return n; -} - -static void __set_subclasses ( - qse_stx_t* stx, qse_word_t* array, const qse_char_t* str) -{ - class_info_t* p; - qse_word_t n = 0, class; - - for (p = class_info; p->name != QSE_NULL; p++) { - if (p->superclass == QSE_NULL) continue; - if (qse_strcmp (str, p->superclass) != 0) continue; - class = qse_stx_lookup_class (stx, p->name); - qse_assert (class != stx->nil); - array[n++] = class; - } -} - -static void __set_metaclass_subclasses ( - qse_stx_t* stx, qse_word_t* array, const qse_char_t* str) -{ - class_info_t* p; - qse_word_t n = 0, class; - - for (p = class_info; p->name != QSE_NULL; p++) { - if (p->superclass == QSE_NULL) continue; - if (qse_strcmp (str, p->superclass) != 0) continue; - class = qse_stx_lookup_class (stx, p->name); - qse_assert (class != stx->nil); - array[n++] = QSE_STX_CLASS(stx,class); - } -} - -static qse_word_t __make_classvar_dict ( - qse_stx_t* stx, qse_word_t class, const qse_char_t* names) -{ - qse_word_t dict, symbol; - const qse_char_t* p = names; - const qse_char_t* name; - - dict = qse_stx_instantiate ( - stx, stx->class_system_dictionary, - QSE_NULL, QSE_NULL, __count_names(names)); - - do { - while (*p == QSE_T(' ') || - *p == QSE_T('\t')) p++; - if (*p == QSE_T('\0')) break; - - name = p; - while (*p != QSE_T(' ') && - *p != QSE_T('\t') && - *p != QSE_T('\0')) p++; - - symbol = qse_stx_new_symbolx (stx, name, p - name); - qse_stx_dict_put (stx, dict, symbol, stx->nil); - } while (1); - - return dict; -} - -static void __filein_kernel (qse_stx_t* stx) -{ - class_info_t* p; - - for (p = class_info; p->name != QSE_NULL; p++) { - /* TODO: */ - } -} - diff --git a/qse/lib/stx/bootstrp.h b/qse/lib/stx/bootstrp.h deleted file mode 100644 index 7a3e6d6e..00000000 --- a/qse/lib/stx/bootstrp.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * $Id: bootstrp.h 118 2008-03-03 11:21:33Z baconevi $ - */ - -#ifndef _QSE_STX_BOOTSTRP_H_ -#define _QSE_STX_BOOTSTRP_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -qse_word_t qse_stx_new_array (qse_stx_t* stx, qse_word_t size); -int qse_stx_bootstrap (qse_stx_t* stx); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/qse/lib/stx/name.c b/qse/lib/stx/name.c deleted file mode 100644 index 8ea23696..00000000 --- a/qse/lib/stx/name.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * $Id: name.c 118 2008-03-03 11:21:33Z baconevi $ - */ - -#include -#include - -qse_stx_name_t* qse_stx_name_open ( - qse_stx_name_t* name, qse_word_t capacity) -{ - if (capacity == 0) - capacity = qse_countof(name->static_buffer) - 1; - - if (name == QSE_NULL) { - name = (qse_stx_name_t*) - qse_malloc (qse_sizeof(qse_stx_name_t)); - if (name == QSE_NULL) return QSE_NULL; - name->__dynamic = qse_true; - } - else name->__dynamic = qse_false; - - if (capacity < qse_countof(name->static_buffer)) { - name->buffer = name->static_buffer; - } - else { - name->buffer = (qse_char_t*) - qse_malloc ((capacity + 1) * qse_sizeof(qse_char_t)); - if (name->buffer == QSE_NULL) { - if (name->__dynamic) qse_free (name); - return QSE_NULL; - } - } - - name->size = 0; - name->capacity = capacity; - name->buffer[0] = QSE_T('\0'); - - return name; -} - -void qse_stx_name_close (qse_stx_name_t* name) -{ - if (name->capacity >= qse_countof(name->static_buffer)) { - qse_assert (name->buffer != name->static_buffer); - qse_free (name->buffer); - } - if (name->__dynamic) qse_free (name); -} - -int qse_stx_name_addc (qse_stx_name_t* name, qse_cint_t c) -{ - if (name->size >= name->capacity) { - /* double the capacity. */ - qse_size_t new_capacity = name->capacity * 2; - - if (new_capacity >= qse_countof(name->static_buffer)) { - qse_char_t* space; - - if (name->capacity < qse_countof(name->static_buffer)) { - space = (qse_char_t*)qse_malloc ( - (new_capacity + 1) * qse_sizeof(qse_char_t)); - if (space == QSE_NULL) return -1; - - /* don't need to copy up to the terminating null */ - qse_memcpy (space, name->buffer, - name->capacity * qse_sizeof(qse_char_t)); - } - else { - space = (qse_char_t*)qse_realloc (name->buffer, - (new_capacity + 1) * qse_sizeof(qse_char_t)); - if (space == QSE_NULL) return -1; - } - - name->buffer = space; - } - - name->capacity = new_capacity; - } - - name->buffer[name->size++] = c; - name->buffer[name->size] = QSE_T('\0'); - return 0; -} - -int qse_stx_name_adds (qse_stx_name_t* name, const qse_char_t* s) -{ - while (*s != QSE_T('\0')) { - if (qse_stx_name_addc(name, *s) == -1) return -1; - s++; - } - - return 0; -} - -void qse_stx_name_clear (qse_stx_name_t* name) -{ - name->size = 0; - name->buffer[0] = QSE_T('\0'); -} - -qse_char_t* qse_stx_name_yield (qse_stx_name_t* name, qse_word_t capacity) -{ - qse_char_t* old_buffer, * new_buffer; - - if (capacity == 0) - capacity = qse_countof(name->static_buffer) - 1; - - if (name->capacity < qse_countof(name->static_buffer)) { - old_buffer = (qse_char_t*) - qse_malloc((name->capacity + 1) * qse_sizeof(qse_char_t)); - if (old_buffer == QSE_NULL) return QSE_NULL; - qse_memcpy (old_buffer, name->buffer, - (name->capacity + 1) * qse_sizeof(qse_char_t)); - } - else old_buffer = name->buffer; - - if (capacity < qse_countof(name->static_buffer)) { - new_buffer = name->static_buffer; - } - else { - new_buffer = (qse_char_t*) - qse_malloc((capacity + 1) * qse_sizeof(qse_char_t)); - if (new_buffer == QSE_NULL) return QSE_NULL; - } - - name->buffer = new_buffer; - name->size = 0; - name->capacity = capacity; - name->buffer[0] = QSE_T('\0'); - - return old_buffer; -} - -int qse_stx_name_compare (qse_stx_name_t* name, const qse_char_t* str) -{ - qse_char_t* p = name->buffer; - qse_word_t index = 0; - - while (index < name->size) { - if (*p > *str) return 1; - if (*p < *str) return -1; - index++; p++; str++; - } - - return (*str == QSE_T('\0'))? 0: -1; -} diff --git a/qse/lib/stx/name.h b/qse/lib/stx/name.h deleted file mode 100644 index 238e8bd4..00000000 --- a/qse/lib/stx/name.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * $Id: name.h 118 2008-03-03 11:21:33Z baconevi $ - */ - -#ifndef _QSE_STX_NAME_H_ -#define _QSE_STX_NAME_H_ - -#include - -struct qse_stx_name_t -{ - qse_word_t capacity; - qse_word_t size; - qse_char_t* buffer; - qse_char_t static_buffer[128]; - qse_bool_t __dynamic; -}; - -typedef struct qse_stx_name_t qse_stx_name_t; - -#ifdef __cplusplus -extern "C" { -#endif - -qse_stx_name_t* qse_stx_name_open ( - qse_stx_name_t* name, qse_word_t capacity); -void qse_stx_name_close (qse_stx_name_t* name); - -int qse_stx_name_addc (qse_stx_name_t* name, qse_cint_t c); -int qse_stx_name_adds (qse_stx_name_t* name, const qse_char_t* s); -void qse_stx_name_clear (qse_stx_name_t* name); -qse_char_t* qse_stx_name_yield (qse_stx_name_t* name, qse_word_t capacity); -int qse_stx_name_compare (qse_stx_name_t* name, const qse_char_t* str); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/qse/lib/stx/par.c b/qse/lib/stx/par.c new file mode 100644 index 00000000..9c0042b5 --- /dev/null +++ b/qse/lib/stx/par.c @@ -0,0 +1,1616 @@ +/* + * $Id$ + */ + +#include "stx.h" + +static int __parse_method ( + qse_stx_parser_t* parser, + qse_word_t method_class, void* input); +static int __finish_method (qse_stx_parser_t* parser); + +static int __parse_message_pattern (qse_stx_parser_t* parser); +static int __parse_unary_pattern (qse_stx_parser_t* parser); +static int __parse_binary_pattern (qse_stx_parser_t* parser); +static int __parse_keyword_pattern (qse_stx_parser_t* parser); + +static int __parse_temporaries (qse_stx_parser_t* parser); +static int __parse_primitive (qse_stx_parser_t* parser); +static int __parse_statements (qse_stx_parser_t* parser); +static int __parse_block_statements (qse_stx_parser_t* parser); +static int __parse_statement (qse_stx_parser_t* parser); +static int __parse_expression (qse_stx_parser_t* parser); + +static int __parse_assignment ( + qse_stx_parser_t* parser, const qse_char_t* target); +static int __parse_basic_expression ( + qse_stx_parser_t* parser, const qse_char_t* ident); +static int __parse_primary ( + qse_stx_parser_t* parser, const qse_char_t* ident, qse_bool_t* is_super); +static int __parse_primary_ident ( + qse_stx_parser_t* parser, const qse_char_t* ident, qse_bool_t* is_super); + +static int __parse_block_constructor (qse_stx_parser_t* parser); +static int __parse_message_continuation ( + qse_stx_parser_t* parser, qse_bool_t is_super); +static int __parse_keyword_message ( + qse_stx_parser_t* parser, qse_bool_t is_super); +static int __parse_binary_message ( + qse_stx_parser_t* parser, qse_bool_t is_super); +static int __parse_unary_message ( + qse_stx_parser_t* parser, qse_bool_t is_super); + +static int __get_token (qse_stx_parser_t* parser); +static int __get_ident (qse_stx_parser_t* parser); +static int __get_numlit (qse_stx_parser_t* parser, qse_bool_t negated); +static int __get_charlit (qse_stx_parser_t* parser); +static int __get_strlit (qse_stx_parser_t* parser); +static int __get_binary (qse_stx_parser_t* parser); +static int __skip_spaces (qse_stx_parser_t* parser); +static int __skip_comment (qse_stx_parser_t* parser); +static int __get_char (qse_stx_parser_t* parser); +static int __unget_char (qse_stx_parser_t* parser, qse_cint_t c); +static int __open_input (qse_stx_parser_t* parser, void* input); +static int __close_input (qse_stx_parser_t* parser); + +qse_stx_parser_t* qse_stx_parser_open (qse_stx_parser_t* parser, qse_stx_t* stx) +{ + if (parser == QSE_NULL) { + parser = (qse_stx_parser_t*) + qse_malloc (qse_sizeof(qse_stx_parser_t)); + if (parser == QSE_NULL) return QSE_NULL; + parser->__dynamic = qse_true; + } + else parser->__dynamic = qse_false; + + if (qse_stx_name_open (&parser->method_name, 0) == QSE_NULL) { + if (parser->__dynamic) qse_free (parser); + return QSE_NULL; + } + + if (qse_stx_token_open (&parser->token, 0) == QSE_NULL) { + qse_stx_name_close (&parser->method_name); + if (parser->__dynamic) qse_free (parser); + return QSE_NULL; + } + + if (qse_arr_open ( + &parser->bytecode, 256, + qse_sizeof(qse_byte_t), QSE_NULL) == QSE_NULL) { + qse_stx_name_close (&parser->method_name); + qse_stx_token_close (&parser->token); + if (parser->__dynamic) qse_free (parser); + return QSE_NULL; + } + + parser->stx = stx; + parser->error_code = QSE_STX_PARSER_ERROR_NONE; + + parser->temporary_count = 0; + parser->argument_count = 0; + parser->literal_count = 0; + + parser->curc = QSE_T_EOF; + parser->ungotc_count = 0; + + parser->input_owner = QSE_NULL; + parser->input_func = QSE_NULL; + return parser; +} + +void qse_stx_parser_close (qse_stx_parser_t* parser) +{ + while (parser->temporary_count > 0) { + qse_free (parser->temporaries[--parser->temporary_count]); + } + parser->argument_count = 0; + + qse_arr_close (&parser->bytecode); + qse_stx_name_close (&parser->method_name); + qse_stx_token_close (&parser->token); + + if (parser->__dynamic) qse_free (parser); +} + +#define GET_CHAR(parser) \ + do { if (__get_char(parser) == -1) return -1; } while (0) +#define UNGET_CHAR(parser,c) \ + do { if (__unget_char(parser,c) == -1) return -1; } while (0) +#define GET_TOKEN(parser) \ + do { if (__get_token(parser) == -1) return -1; } while (0) +#define ADD_TOKEN_CHAR(parser,c) \ + do { \ + if (qse_stx_token_addc (&(parser)->token, c) == -1) { \ + (parser)->error_code = QSE_STX_PARSER_ERROR_MEMORY; \ + return -1; \ + } \ + } while (0) + +const qse_char_t* qse_stx_parser_error_string (qse_stx_parser_t* parser) +{ + static const qse_char_t* msg[] = + { + QSE_T("no error"), + + QSE_T("input fucntion not ready"), + QSE_T("input function error"), + QSE_T("out of memory"), + + QSE_T("invalid character"), + QSE_T("incomplete character literal"), + QSE_T("incomplete string literal"), + QSE_T("incomplete literal"), + + QSE_T("message selector"), + QSE_T("invalid argument name"), + QSE_T("too many arguments"), + + QSE_T("invalid primitive type"), + QSE_T("primitive number expected"), + QSE_T("primitive number out of range"), + QSE_T("primitive not closed"), + + QSE_T("temporary list not closed"), + QSE_T("too many temporaries"), + QSE_T("cannot redefine pseudo variable"), + QSE_T("invalid primary/expression-start"), + + QSE_T("no period at end of statement"), + QSE_T("no closing parenthesis"), + QSE_T("block argument name missing"), + QSE_T("block argument list not closed"), + QSE_T("block not closed"), + + QSE_T("undeclared name"), + QSE_T("too many literals") + }; + + if (parser->error_code >= 0 && + parser->error_code < qse_countof(msg)) return msg[parser->error_code]; + + return QSE_T("unknown error"); +} + +static INLINE qse_bool_t __is_pseudo_variable (const qse_stx_token_t* token) +{ + return token->type == QSE_STX_TOKEN_IDENT && + (qse_strcmp(token->name.buffer, QSE_T("self")) == 0 || + qse_strcmp(token->name.buffer, QSE_T("super")) == 0 || + qse_strcmp(token->name.buffer, QSE_T("nil")) == 0 || + qse_strcmp(token->name.buffer, QSE_T("true")) == 0 || + qse_strcmp(token->name.buffer, QSE_T("false")) == 0); +} + +static INLINE qse_bool_t __is_vbar_token (const qse_stx_token_t* token) +{ + return + token->type == QSE_STX_TOKEN_BINARY && + token->name.size == 1 && + token->name.buffer[0] == QSE_T('|'); +} + +static INLINE qse_bool_t __is_primitive_opener (const qse_stx_token_t* token) +{ + return + token->type == QSE_STX_TOKEN_BINARY && + token->name.size == 1 && + token->name.buffer[0] == QSE_T('<'); +} + +static INLINE qse_bool_t __is_primitive_closer (const qse_stx_token_t* token) +{ + return + token->type == QSE_STX_TOKEN_BINARY && + token->name.size == 1 && + token->name.buffer[0] == QSE_T('>'); +} + +static INLINE qse_bool_t __is_binary_char (qse_cint_t c) +{ + /* + * binaryCharacter ::= + * '!' | '%' | '&' | '*' | '+' | ',' | + * '/' | '<' | '=' | '>' | '?' | '@' | + * '\' | '~' | '|' | '-' + */ + + return + c == QSE_T('!') || c == QSE_T('%') || + c == QSE_T('&') || c == QSE_T('*') || + c == QSE_T('+') || c == QSE_T(',') || + c == QSE_T('/') || c == QSE_T('<') || + c == QSE_T('=') || c == QSE_T('>') || + c == QSE_T('?') || c == QSE_T('@') || + c == QSE_T('\\') || c == QSE_T('|') || + c == QSE_T('~') || c == QSE_T('-'); +} + +static INLINE qse_bool_t __is_closing_char (qse_cint_t c) +{ + return + c == QSE_T('.') || c == QSE_T(']') || + c == QSE_T(')') || c == QSE_T(';') || + c == QSE_T('\"') || c == QSE_T('\''); +} + +#define EMIT_CODE_TEST(parser,high,low) \ + do { if (__emit_code_test(parser,high,low) == -1) return -1; } while (0) + +#define EMIT_CODE(parser,code) \ + do { if (__emit_code(parser,code) == -1) return -1; } while(0) + +#define EMIT_PUSH_RECEIVER_VARIABLE(parser,pos) \ + do { \ + if (__emit_stack_positional ( \ + parser, PUSH_RECEIVER_VARIABLE, pos) == -1) return -1; \ + } while (0) + +#define EMIT_PUSH_TEMPORARY_LOCATION(parser,pos) \ + do { \ + if (__emit_stack_positional ( \ + parser, PUSH_TEMPORARY_LOCATION, pos) == -1) return -1; \ + } while (0) + +#define EMIT_PUSH_LITERAL_CONSTANT(parser,pos) \ + do { \ + if (__emit_stack_positional ( \ + parser, PUSH_LITERAL_CONSTANT, pos) == -1) return -1; \ + } while (0) + + +#define EMIT_PUSH_LITERAL_VARIABLE(parser,pos) \ + do { \ + if (__emit_stack_positional ( \ + parser, PUSH_LITERAL_VARIABLE, pos) == -1) return -1; \ + } while (0) + +#define EMIT_STORE_RECEIVER_VARIABLE(parser,pos) \ + do { \ + if (__emit_stack_positional ( \ + parser, STORE_RECEIVER_VARIABLE, pos) == -1) return -1; \ + } while (0) + +#define EMIT_STORE_TEMPORARY_LOCATION(parser,pos) \ + do { \ + if (__emit_stack_positional ( \ + parser, STORE_TEMPORARY_LOCATION, pos) == -1) return -1; \ + } while (0) + + +#define EMIT_POP_STACK_TOP(parser) EMIT_CODE(parser, POP_STACK_TOP) +#define EMIT_DUPLICATE_STACK_TOP(parser) EMIT_CODE(parser, DUPLICATE_STACK_TOP) +#define EMIT_PUSH_ACTIVE_CONTEXT(parser) EMIT_CODE(parser, PUSH_ACTIVE_CONTEXT) +#define EMIT_RETURN_FROM_MESSAGE(parser) EMIT_CODE(parser, RETURN_FROM_MESSAGE) +#define EMIT_RETURN_FROM_BLOCK(parser) EMIT_CODE(parser, RETURN_FROM_BLOCK) + +#define EMIT_SEND_TO_SELF(parser,nargs,selector) \ + do { \ + if (__emit_send_to_self(parser,nargs,selector) == -1) return -1; \ + } while (0) + +#define EMIT_SEND_TO_SUPER(parser,nargs,selector) \ + do { \ + if (__emit_send_to_super(parser,nargs,selector) == -1) return -1; \ + } while (0) + +#define EMIT_DO_PRIMITIVE(parser,no) \ + do { if (__emit_do_primitive(parser,no) == -1) return -1; } while(0) + +static INLINE int __emit_code_test ( + qse_stx_parser_t* parser, const qse_char_t* high, const qse_char_t* low) +{ + qse_printf (QSE_T("CODE: %s %s\n"), high, low); + return 0; +} + +static INLINE int __emit_code (qse_stx_parser_t* parser, qse_byte_t code) +{ + if (qse_arr_adddatum(&parser->bytecode, &code) == QSE_NULL) { + parser->error_code = QSE_STX_PARSER_ERROR_MEMORY; + return -1; + } + + return 0; +} + +static INLINE int __emit_stack_positional ( + qse_stx_parser_t* parser, int opcode, int pos) +{ + qse_assert (pos >= 0x0 && pos <= 0xFF); + + if (pos <= 0x0F) { + EMIT_CODE (parser, (opcode & 0xF0) | (pos & 0x0F)); + } + else { + EMIT_CODE (parser, (opcode >> 4) & 0x6F); + EMIT_CODE (parser, pos & 0xFF); + } + + return 0; +} + +static INLINE int __emit_send_to_self ( + qse_stx_parser_t* parser, int nargs, int selector) +{ + qse_assert (nargs >= 0x00 && nargs <= 0xFF); + qse_assert (selector >= 0x00 && selector <= 0xFF); + + if (nargs <= 0x08 && selector <= 0x1F) { + EMIT_CODE (parser, SEND_TO_SELF); + EMIT_CODE (parser, (nargs << 5) | selector); + } + else { + EMIT_CODE (parser, SEND_TO_SELF_EXTENDED); + EMIT_CODE (parser, nargs); + EMIT_CODE (parser, selector); + } + + return 0; +} + +static INLINE int __emit_send_to_super ( + qse_stx_parser_t* parser, int nargs, int selector) +{ + qse_assert (nargs >= 0x00 && nargs <= 0xFF); + qse_assert (selector >= 0x00 && selector <= 0xFF); + + if (nargs <= 0x08 && selector <= 0x1F) { + EMIT_CODE (parser, SEND_TO_SUPER); + EMIT_CODE (parser, (nargs << 5) | selector); + } + else { + EMIT_CODE (parser, SEND_TO_SUPER_EXTENDED); + EMIT_CODE (parser, nargs); + EMIT_CODE (parser, selector); + } + + return 0; +} + +static INLINE int __emit_do_primitive (qse_stx_parser_t* parser, int no) +{ + qse_assert (no >= 0x0 && no <= 0xFFF); + + EMIT_CODE (parser, DO_PRIMITIVE | ((no >> 8) & 0x0F)); + EMIT_CODE (parser, no & 0xFF); + + return 0; +} + +static int __add_literal (qse_stx_parser_t* parser, qse_word_t literal) +{ + qse_word_t i; + + for (i = 0; i < parser->literal_count; i++) { + /* + * it would remove redundancy of symbols and small integers. + * more complex redundacy check may be done somewhere else + * like in __add_string_literal. + */ + if (parser->literals[i] == literal) return i; + } + + if (parser->literal_count >= qse_countof(parser->literals)) { + parser->error_code = QSE_STX_PARSER_ERROR_TOO_MANY_LITERALS; + return -1; + } + + parser->literals[parser->literal_count++] = literal; + return parser->literal_count - 1; +} + +static int __add_character_literal (qse_stx_parser_t* parser, qse_char_t ch) +{ + qse_word_t i, c, literal; + qse_stx_t* stx = parser->stx; + + for (i = 0; i < parser->literal_count; i++) { + c = QSE_STX_ISSMALLINT(parser->literals[i])? + stx->class_smallinteger: QSE_STX_CLASS (stx, parser->literals[i]); + if (c != stx->class_character) continue; + + if (ch == QSE_STX_CHAR_AT(stx,parser->literals[i],0)) return i; + } + + literal = qse_stx_instantiate ( + stx, stx->class_character, &ch, QSE_NULL, 0); + return __add_literal (parser, literal); +} + +static int __add_string_literal ( + qse_stx_parser_t* parser, const qse_char_t* str, qse_word_t size) +{ + qse_word_t i, c, literal; + qse_stx_t* stx = parser->stx; + + for (i = 0; i < parser->literal_count; i++) { + c = QSE_STX_ISSMALLINT(parser->literals[i])? + stx->class_smallinteger: QSE_STX_CLASS (stx, parser->literals[i]); + if (c != stx->class_string) continue; + + if (qse_strxncmp (str, size, + QSE_STX_DATA(stx,parser->literals[i]), + QSE_STX_SIZE(stx,parser->literals[i])) == 0) return i; + } + + literal = qse_stx_instantiate ( + stx, stx->class_string, QSE_NULL, str, size); + return __add_literal (parser, literal); +} + +static int __add_symbol_literal ( + qse_stx_parser_t* parser, const qse_char_t* str, qse_word_t size) +{ + qse_stx_t* stx = parser->stx; + return __add_literal (parser, qse_stx_new_symbolx(stx, str, size)); +} + +int qse_stx_parser_parse_method ( + qse_stx_parser_t* parser, qse_word_t method_class, void* input) +{ + int n; + + if (parser->input_func == QSE_NULL) { + parser->error_code = QSE_STX_PARSER_ERROR_INPUT_FUNC; + return -1; + } + + parser->method_class = method_class; + if (__open_input(parser, input) == -1) return -1; + n = __parse_method (parser, method_class, input); + if (__close_input(parser) == -1) return -1; + + return n; +} + +static int __parse_method ( + qse_stx_parser_t* parser, qse_word_t method_class, void* input) +{ + /* + * ::= + * [] [] [] + */ + + GET_CHAR (parser); + GET_TOKEN (parser); + + qse_stx_name_clear (&parser->method_name); + qse_arr_clear (&parser->bytecode); + + while (parser->temporary_count > 0) { + qse_free (parser->temporaries[--parser->temporary_count]); + } + parser->argument_count = 0; + parser->literal_count = 0; + + if (__parse_message_pattern(parser) == -1) return -1; + if (__parse_temporaries(parser) == -1) return -1; + if (__parse_primitive(parser) == -1) return -1; + if (__parse_statements(parser) == -1) return -1; + if (__finish_method (parser) == -1) return -1; + + return 0; +} + +static int __finish_method (qse_stx_parser_t* parser) +{ + qse_stx_t* stx = parser->stx; + qse_stx_class_t* class_obj; + qse_stx_method_t* method_obj; + qse_word_t method, selector; + + qse_assert (parser->bytecode.size != 0); + + class_obj = (qse_stx_class_t*) + QSE_STX_OBJPTR(stx, parser->method_class); + + if (class_obj->methods == stx->nil) { + /* TODO: reconfigure method dictionary size */ + class_obj->methods = qse_stx_instantiate ( + stx, stx->class_system_dictionary, + QSE_NULL, QSE_NULL, 64); + } + qse_assert (class_obj->methods != stx->nil); + + selector = qse_stx_new_symbolx ( + stx, parser->method_name.buffer, parser->method_name.size); + + method = qse_stx_instantiate(stx, stx->class_method, + QSE_NULL, parser->literals, parser->literal_count); + method_obj = (qse_stx_method_t*)QSE_STX_OBJPTR(stx, method); + + /* TODO: text saving must be optional */ + /*method_obj->text = qse_stx_instantiate ( + stx, stx->class_string, QSE_NULL, + parser->text, qse_strlen(parser->text)); + */ + method_obj->selector = selector; + method_obj->bytecodes = qse_stx_instantiate ( + stx, stx->class_bytearray, QSE_NULL, + parser->bytecode.buf, parser->bytecode.size); + + /* TODO: better way to store argument count & temporary count */ + method_obj->tmpcount = + QSE_STX_TO_SMALLINT(parser->temporary_count - parser->argument_count); + method_obj->argcount = QSE_STX_TO_SMALLINT(parser->argument_count); + + qse_stx_dict_put (stx, class_obj->methods, selector, method); + return 0; +} + +static int __parse_message_pattern (qse_stx_parser_t* parser) +{ + /* + * ::= + * | | + * ::= unarySelector + * ::= binarySelector + * ::= (keyword )+ + */ + int n; + + if (parser->token.type == QSE_STX_TOKEN_IDENT) { + n = __parse_unary_pattern (parser); + } + else if (parser->token.type == QSE_STX_TOKEN_BINARY) { + n = __parse_binary_pattern (parser); + } + else if (parser->token.type == QSE_STX_TOKEN_KEYWORD) { + n = __parse_keyword_pattern (parser); + } + else { + parser->error_code = QSE_STX_PARSER_ERROR_MESSAGE_SELECTOR; + n = -1; + } + + parser->temporary_count = parser->argument_count; + return n; +} + +static int __parse_unary_pattern (qse_stx_parser_t* parser) +{ + /* TODO: check if the method name exists */ + + if (qse_stx_name_adds( + &parser->method_name, parser->token.name.buffer) == -1) { + parser->error_code = QSE_STX_PARSER_ERROR_MEMORY; + return -1; + } + + GET_TOKEN (parser); + return 0; +} + +static int __parse_binary_pattern (qse_stx_parser_t* parser) +{ + /* TODO: check if the method name exists */ + + if (qse_stx_name_adds( + &parser->method_name, parser->token.name.buffer) == -1) { + parser->error_code = QSE_STX_PARSER_ERROR_MEMORY; + return -1; + } + + GET_TOKEN (parser); + if (parser->token.type != QSE_STX_TOKEN_IDENT) { + parser->error_code = QSE_STX_PARSER_ERROR_ARGUMENT_NAME; + return -1; + } + + if (parser->argument_count >= qse_countof(parser->temporaries)) { + parser->error_code = QSE_STX_PARSER_ERROR_TOO_MANY_ARGUMENTS; + return -1; + } + + /* TODO: check for duplicate entries...in instvars */ + parser->temporaries[parser->argument_count] = + qse_stx_token_yield (&parser->token, 0); + if (parser->temporaries[parser->argument_count] == QSE_NULL) { + parser->error_code = QSE_STX_PARSER_ERROR_MEMORY; + return -1; + } + parser->argument_count++; + + GET_TOKEN (parser); + return 0; +} + +static int __parse_keyword_pattern (qse_stx_parser_t* parser) +{ + do { + if (qse_stx_name_adds( + &parser->method_name, parser->token.name.buffer) == -1) { + parser->error_code = QSE_STX_PARSER_ERROR_MEMORY; + return -1; + } + + GET_TOKEN (parser); + if (parser->token.type != QSE_STX_TOKEN_IDENT) { + parser->error_code = QSE_STX_PARSER_ERROR_ARGUMENT_NAME; + return -1; + } + + if (__is_pseudo_variable(&parser->token)) { + parser->error_code = QSE_STX_PARSER_ERROR_PSEUDO_VARIABLE; + return -1; + } + + if (parser->argument_count >= qse_countof(parser->temporaries)) { + parser->error_code = QSE_STX_PARSER_ERROR_TOO_MANY_ARGUMENTS; + return -1; + } + + parser->temporaries[parser->argument_count] = + qse_stx_token_yield (&parser->token, 0); + if (parser->temporaries[parser->argument_count] == QSE_NULL) { + parser->error_code = QSE_STX_PARSER_ERROR_MEMORY; + return -1; + } + +/* TODO: check for duplicate entries...in instvars/arguments */ + parser->argument_count++; + + GET_TOKEN (parser); + } while (parser->token.type == QSE_STX_TOKEN_KEYWORD); + + /* TODO: check if the method name exists */ + /* if it exists, collapse arguments */ +qse_printf (QSE_T("METHOD NAME ==> [%s]\n"), parser->method_name.buffer); + + return 0; +} + +static int __parse_temporaries (qse_stx_parser_t* parser) +{ + /* + * ::= '|' '|' + * ::= identifier* + */ + + if (!__is_vbar_token(&parser->token)) return 0; + + GET_TOKEN (parser); + while (parser->token.type == QSE_STX_TOKEN_IDENT) { + if (parser->temporary_count >= qse_countof(parser->temporaries)) { + parser->error_code = QSE_STX_PARSER_ERROR_TOO_MANY_TEMPORARIES; + return -1; + } + + if (__is_pseudo_variable(&parser->token)) { + parser->error_code = QSE_STX_PARSER_ERROR_PSEUDO_VARIABLE; + return -1; + } + + parser->temporaries[parser->temporary_count] = + qse_stx_token_yield (&parser->token, 0); + if (parser->temporaries[parser->temporary_count] == QSE_NULL) { + parser->error_code = QSE_STX_PARSER_ERROR_MEMORY; + return -1; + } + +/* TODO: check for duplicate entries...in instvars/arguments/temporaries */ + parser->temporary_count++; + + GET_TOKEN (parser); + } + if (!__is_vbar_token(&parser->token)) { + parser->error_code = QSE_STX_PARSER_ERROR_TEMPORARIES_NOT_CLOSED; + return -1; + } + + GET_TOKEN (parser); + return 0; +} + +static int __parse_primitive (qse_stx_parser_t* parser) +{ + /* + * ::= '<' 'primitive:' number '>' + */ + + int prim_no; + + if (!__is_primitive_opener(&parser->token)) return 0; + GET_TOKEN (parser); + + if (parser->token.type != QSE_STX_TOKEN_KEYWORD || + qse_strcmp (parser->token.name.buffer, QSE_T("primitive:")) != 0) { + parser->error_code = QSE_STX_PARSER_ERROR_PRIMITIVE_KEYWORD; + return -1; + } + + GET_TOKEN (parser); /* TODO: only integer */ + if (parser->token.type != QSE_STX_TOKEN_NUMLIT) { + parser->error_code = QSE_STX_PARSER_ERROR_PRIMITIVE_NUMBER; + return -1; + } + +/*TODO: more checks the validity of the primitive number */ + if (!qse_stristype(parser->token.name.buffer, qse_isdigit)) { + parser->error_code = QSE_STX_PARSER_ERROR_PRIMITIVE_NUMBER; + return -1; + } + + QSE_STRTOI (prim_no, parser->token.name.buffer, QSE_NULL, 10); + if (prim_no < 0 || prim_no > 0xFF) { + parser->error_code = QSE_STX_PARSER_ERROR_PRIMITIVE_NUMBER_RANGE; + return -1; + } + + EMIT_DO_PRIMITIVE (parser, prim_no); + + GET_TOKEN (parser); + if (!__is_primitive_closer(&parser->token)) { + parser->error_code = QSE_STX_PARSER_ERROR_PRIMITIVE_NOT_CLOSED; + return -1; + } + + GET_TOKEN (parser); + return 0; +} + +static int __parse_statements (qse_stx_parser_t* parser) +{ + /* + * ::= (ORIGINAL->maybe wrong) + * ( ['.'] ) | + * ( ['.' []]) + * ::= (REVISED->correct?) + * ['. []] + */ + + while (parser->token.type != QSE_STX_TOKEN_END) { + if (__parse_statement (parser) == -1) return -1; + + if (parser->token.type == QSE_STX_TOKEN_PERIOD) { + GET_TOKEN (parser); + continue; + } + + if (parser->token.type != QSE_STX_TOKEN_END) { + parser->error_code = QSE_STX_PARSER_ERROR_NO_PERIOD; + return -1; + } + } + + EMIT_CODE (parser, RETURN_RECEIVER); + return 0; +} + +static int __parse_block_statements (qse_stx_parser_t* parser) +{ + while (parser->token.type != QSE_STX_TOKEN_RBRACKET && + parser->token.type != QSE_STX_TOKEN_END) { + + if (__parse_statement(parser) == -1) return -1; + if (parser->token.type != QSE_STX_TOKEN_PERIOD) break; + GET_TOKEN (parser); + } + + return 0; +} + +static int __parse_statement (qse_stx_parser_t* parser) +{ + /* + * ::= | + * ::= returnOperator + * returnOperator ::= '^' + */ + + if (parser->token.type == QSE_STX_TOKEN_RETURN) { + GET_TOKEN (parser); + if (__parse_expression(parser) == -1) return -1; + EMIT_RETURN_FROM_MESSAGE (parser); + } + else { + if (__parse_expression(parser) == -1) return -1; + } + + return 0; +} + +static int __parse_expression (qse_stx_parser_t* parser) +{ + /* + * ::= | + * ::= assignmentOperator + * ::= [ ] + * ::= identifier + * assignmentOperator ::= ':=' + */ + qse_stx_t* stx = parser->stx; + + if (parser->token.type == QSE_STX_TOKEN_IDENT) { + qse_char_t* ident = qse_stx_token_yield (&parser->token, 0); + if (ident == QSE_NULL) { + parser->error_code = QSE_STX_PARSER_ERROR_MEMORY; + return -1; + } + + GET_TOKEN (parser); + if (parser->token.type == QSE_STX_TOKEN_ASSIGN) { + GET_TOKEN (parser); + if (__parse_assignment(parser, ident) == -1) { + qse_free (ident); + return -1; + } + } + else { + if (__parse_basic_expression(parser, ident) == -1) { + qse_free (ident); + return -1; + } + } + + qse_free (ident); + } + else { + if (__parse_basic_expression(parser, QSE_NULL) == -1) return -1; + } + + return 0; +} + +static int __parse_basic_expression ( + qse_stx_parser_t* parser, const qse_char_t* ident) +{ + /* + * ::= [ ] + */ + qse_bool_t is_super; + + if (__parse_primary(parser, ident, &is_super) == -1) return -1; + if (parser->token.type != QSE_STX_TOKEN_END && + parser->token.type != QSE_STX_TOKEN_PERIOD) { + if (__parse_message_continuation(parser, is_super) == -1) return -1; + } + return 0; +} + +static int __parse_assignment ( + qse_stx_parser_t* parser, const qse_char_t* target) +{ + /* + * ::= assignmentOperator + */ + + qse_word_t i; + qse_stx_t* stx = parser->stx; + + for (i = parser->argument_count; i < parser->temporary_count; i++) { + if (qse_strcmp (target, parser->temporaries[i]) == 0) { + if (__parse_expression(parser) == -1) return -1; + EMIT_STORE_TEMPORARY_LOCATION (parser, i); + return 0; + } + } + + if (qse_stx_get_instance_variable_index ( + stx, parser->method_class, target, &i) == 0) { + if (__parse_expression(parser) == -1) return -1; + EMIT_STORE_RECEIVER_VARIABLE (parser, i); + return 0; + } + + if (qse_stx_lookup_class_variable ( + stx, parser->method_class, target) != stx->nil) { + if (__parse_expression(parser) == -1) return -1; + + /* TODO */ + EMIT_CODE_TEST (parser, QSE_T("ASSIGN_CLASSVAR #"), target); + //EMIT_STORE_CLASS_VARIABLE (parser, target); + return 0; + } + + /* TODO: IMPLEMENT POOL DICTIONARIES */ + + /* TODO: IMPLEMENT GLOBLAS, but i don't like this idea */ + + parser->error_code = QSE_STX_PARSER_ERROR_UNDECLARED_NAME; + return -1; +} + +static int __parse_primary ( + qse_stx_parser_t* parser, const qse_char_t* ident, qse_bool_t* is_super) +{ + /* + * ::= + * identifier | | + * | ( '('')' ) + */ + + qse_stx_t* stx = parser->stx; + + if (ident == QSE_NULL) { + int pos; + qse_word_t literal; + + *is_super = qse_false; + + if (parser->token.type == QSE_STX_TOKEN_IDENT) { + if (__parse_primary_ident(parser, + parser->token.name.buffer, is_super) == -1) return -1; + GET_TOKEN (parser); + } + else if (parser->token.type == QSE_STX_TOKEN_CHARLIT) { + pos = __add_character_literal( + parser, parser->token.name.buffer[0]); + if (pos == -1) return -1; + EMIT_PUSH_LITERAL_CONSTANT (parser, pos); + GET_TOKEN (parser); + } + else if (parser->token.type == QSE_STX_TOKEN_STRLIT) { + pos = __add_string_literal (parser, + parser->token.name.buffer, parser->token.name.size); + if (pos == -1) return -1; + EMIT_PUSH_LITERAL_CONSTANT (parser, pos); + GET_TOKEN (parser); + } + else if (parser->token.type == QSE_STX_TOKEN_NUMLIT) { + /* TODO: other types of numbers, negative numbers, etc */ + qse_word_t tmp; + QSE_STRTOI (tmp, parser->token.name.buffer, QSE_NULL, 10); + literal = QSE_STX_TO_SMALLINT(tmp); + pos = __add_literal(parser, literal); + if (pos == -1) return -1; + EMIT_PUSH_LITERAL_CONSTANT (parser, pos); + GET_TOKEN (parser); + } + else if (parser->token.type == QSE_STX_TOKEN_SYMLIT) { + pos = __add_symbol_literal (parser, + parser->token.name.buffer, parser->token.name.size); + if (pos == -1) return -1; + EMIT_PUSH_LITERAL_CONSTANT (parser, pos); + GET_TOKEN (parser); + } + else if (parser->token.type == QSE_STX_TOKEN_LBRACKET) { + GET_TOKEN (parser); + if (__parse_block_constructor(parser) == -1) return -1; + } + else if (parser->token.type == QSE_STX_TOKEN_APAREN) { + /* TODO: array literal */ + } + else if (parser->token.type == QSE_STX_TOKEN_LPAREN) { + GET_TOKEN (parser); + if (__parse_expression(parser) == -1) return -1; + if (parser->token.type != QSE_STX_TOKEN_RPAREN) { + parser->error_code = QSE_STX_PARSER_ERROR_NO_RPAREN; + return -1; + } + GET_TOKEN (parser); + } + else { + parser->error_code = QSE_STX_PARSER_ERROR_PRIMARY; + return -1; + } + } + else { + /*if (__parse_primary_ident(parser, parser->token.name.buffer) == -1) return -1;*/ + if (__parse_primary_ident(parser, ident, is_super) == -1) return -1; + } + + return 0; +} + +static int __parse_primary_ident ( + qse_stx_parser_t* parser, const qse_char_t* ident, qse_bool_t* is_super) +{ + qse_word_t i; + qse_stx_t* stx = parser->stx; + + *is_super = qse_false; + + if (qse_strcmp(ident, QSE_T("self")) == 0) + { + EMIT_CODE (parser, PUSH_RECEIVER); + return 0; + } + else if (qse_strcmp(ident, QSE_T("super")) == 0) + { + *is_super = qse_true; + EMIT_CODE (parser, PUSH_RECEIVER); + return 0; + } + else if (qse_strcmp(ident, QSE_T("nil")) == 0) + { + EMIT_CODE (parser, PUSH_NIL); + return 0; + } + else if (qse_strcmp(ident, QSE_T("true")) == 0) + { + EMIT_CODE (parser, PUSH_TRUE); + return 0; + } + else if (qse_strcmp(ident, QSE_T("false")) == 0) + { + EMIT_CODE (parser, PUSH_FALSE); + return 0; + } + + /* Refer to __parse_assignment for identifier lookup */ + + for (i = 0; i < parser->temporary_count; i++) + { + if (qse_strcmp(ident, parser->temporaries[i]) == 0) + { + EMIT_PUSH_TEMPORARY_LOCATION (parser, i); + return 0; + } + } + + if (qse_stx_get_instance_variable_index ( + stx, parser->method_class, ident, &i) == 0) + { + EMIT_PUSH_RECEIVER_VARIABLE (parser, i); + return 0; + } + + /* TODO: what is the best way to look up a class variable? */ + /* 1. Use the class containing it and using its position */ + /* 2. Use a primitive method after pushing the name as a symbol */ + /* 3. Implement a vm instruction to do it */ +/* + if (qse_stx_lookup_class_variable ( + stx, parser->method_class, ident) != stx->nil) { + //EMIT_LOOKUP_CLASS_VARIABLE (parser, ident); + return 0; + } +*/ + + /* TODO: IMPLEMENT POOL DICTIONARIES */ + + /* TODO: IMPLEMENT GLOBLAS, but i don't like this idea */ + + parser->error_code = QSE_STX_PARSER_ERROR_UNDECLARED_NAME; + return -1; +} + +static int __parse_block_constructor (qse_stx_parser_t* parser) +{ + /* + * ::= '[' ']' + * ::= [* '|'] + * [] [] + * ::= ':' identifier + */ + + if (parser->token.type == QSE_STX_TOKEN_COLON) + { + do + { + GET_TOKEN (parser); + + if (parser->token.type != QSE_STX_TOKEN_IDENT) + { + parser->error_code = QSE_STX_PARSER_ERROR_BLOCK_ARGUMENT_NAME; + return -1; + } + + /* TODO : store block arguments */ + GET_TOKEN (parser); + } + while (parser->token.type == QSE_STX_TOKEN_COLON); + + if (!__is_vbar_token(&parser->token)) + { + parser->error_code = QSE_STX_PARSER_ERROR_BLOCK_ARGUMENT_LIST; + return -1; + } + + GET_TOKEN (parser); + } + + /* TODO: create a block closure */ + if (__parse_temporaries(parser) == -1) return -1; + if (__parse_block_statements(parser) == -1) return -1; + + if (parser->token.type != QSE_STX_TOKEN_RBRACKET) + { + parser->error_code = QSE_STX_PARSER_ERROR_BLOCK_NOT_CLOSED; + return -1; + } + + GET_TOKEN (parser); + + /* TODO: do special treatment for block closures */ + + return 0; +} + +static int __parse_message_continuation ( + qse_stx_parser_t* parser, qse_bool_t is_super) +{ + /* + * ::= + * (+ * [] ) | + * (+ [] ) | + * + * ::= (';' )* + */ + if (__parse_keyword_message(parser, is_super) == -1) return -1; + + while (parser->token.type == QSE_STX_TOKEN_SEMICOLON) + { + EMIT_CODE_TEST (parser, QSE_T("DoSpecial(DUP_RECEIVER(CASCADE))"), QSE_T("")); + GET_TOKEN (parser); + + if (__parse_keyword_message(parser, qse_false) == -1) return -1; + EMIT_CODE_TEST (parser, QSE_T("DoSpecial(POP_TOP)"), QSE_T("")); + } + + return 0; +} + +static int __parse_keyword_message (qse_stx_parser_t* parser, qse_bool_t is_super) +{ + /* + * ::= (keyword )+ + * ::= * * + */ + + qse_stx_name_t name; + qse_word_t pos; + qse_bool_t is_super2; + int nargs = 0, n; + + if (__parse_binary_message (parser, is_super) == -1) return -1; + if (parser->token.type != QSE_STX_TOKEN_KEYWORD) return 0; + + if (qse_stx_name_open(&name, 0) == QSE_NULL) { + parser->error_code = QSE_STX_PARSER_ERROR_MEMORY; + return -1; + } + + do { + if (qse_stx_name_adds(&name, parser->token.name.buffer) == -1) { + parser->error_code = QSE_STX_PARSER_ERROR_MEMORY; + qse_stx_name_close (&name); + return -1; + } + + GET_TOKEN (parser); + if (__parse_primary(parser, QSE_NULL, &is_super2) == -1) { + qse_stx_name_close (&name); + return -1; + } + + if (__parse_binary_message(parser, is_super2) == -1) { + qse_stx_name_close (&name); + return -1; + } + + nargs++; + /* TODO: check if it has too many arguments.. */ + } while (parser->token.type == QSE_STX_TOKEN_KEYWORD); + + pos = __add_symbol_literal (parser, name.buffer, name.size); + if (pos == -1) { + qse_stx_name_close (&name); + return -1; + } + + n = (is_super)? + __emit_send_to_super(parser,nargs,pos): + __emit_send_to_self(parser,nargs,pos); + if (n == -1) { + qse_stx_name_close (&name); + return -1; + } + + qse_stx_name_close (&name); + return 0; +} + +static int __parse_binary_message (qse_stx_parser_t* parser, qse_bool_t is_super) +{ + /* + * ::= binarySelector + * ::= * + */ + qse_word_t pos; + qse_bool_t is_super2; + int n; + + if (__parse_unary_message (parser, is_super) == -1) return -1; + + while (parser->token.type == QSE_STX_TOKEN_BINARY) { + qse_char_t* op = qse_stx_token_yield (&parser->token, 0); + if (op == QSE_NULL) { + parser->error_code = QSE_STX_PARSER_ERROR_MEMORY; + return -1; + } + + GET_TOKEN (parser); + if (__parse_primary(parser, QSE_NULL, &is_super2) == -1) { + qse_free (op); + return -1; + } + + if (__parse_unary_message(parser, is_super2) == -1) { + qse_free (op); + return -1; + } + + pos = __add_symbol_literal (parser, op, qse_strlen(op)); + if (pos == -1) { + qse_free (op); + return -1; + } + + n = (is_super)? + __emit_send_to_super(parser,2,pos): + __emit_send_to_self(parser,2,pos); + if (n == -1) { + qse_free (op); + return -1; + } + + qse_free (op); + } + + return 0; +} + +static int __parse_unary_message (qse_stx_parser_t* parser, qse_bool_t is_super) +{ + /* ::= unarySelector */ + + qse_word_t pos; + int n; + + while (parser->token.type == QSE_STX_TOKEN_IDENT) { + pos = __add_symbol_literal (parser, + parser->token.name.buffer, parser->token.name.size); + if (pos == -1) return -1; + + n = (is_super)? + __emit_send_to_super(parser,0,pos): + __emit_send_to_self(parser,0,pos); + if (n == -1) return -1; + + GET_TOKEN (parser); + } + + return 0; +} + +static int __get_token (qse_stx_parser_t* parser) +{ + qse_cint_t c; + + do { + if (__skip_spaces(parser) == -1) return -1; + if (parser->curc == QSE_T('"')) { + GET_CHAR (parser); + if (__skip_comment(parser) == -1) return -1; + } + else break; + } while (1); + + c = parser->curc; + qse_stx_token_clear (&parser->token); + + if (c == QSE_T_EOF) { + parser->token.type = QSE_STX_TOKEN_END; + } + else if (qse_isalpha(c)) { + if (__get_ident(parser) == -1) return -1; + } + else if (qse_isdigit(c)) { + if (__get_numlit(parser, qse_false) == -1) return -1; + } + else if (c == QSE_T('$')) { + GET_CHAR (parser); + if (__get_charlit(parser) == -1) return -1; + } + else if (c == QSE_T('\'')) { + GET_CHAR (parser); + if (__get_strlit(parser) == -1) return -1; + } + else if (c == QSE_T(':')) { + parser->token.type = QSE_STX_TOKEN_COLON; + ADD_TOKEN_CHAR(parser, c); + GET_CHAR (parser); + + c = parser->curc; + if (c == QSE_T('=')) { + parser->token.type = QSE_STX_TOKEN_ASSIGN; + ADD_TOKEN_CHAR(parser, c); + GET_CHAR (parser); + } + } + else if (c == QSE_T('^')) { + parser->token.type = QSE_STX_TOKEN_RETURN; + ADD_TOKEN_CHAR(parser, c); + GET_CHAR (parser); + } + else if (c == QSE_T('[')) { + parser->token.type = QSE_STX_TOKEN_LBRACKET; + ADD_TOKEN_CHAR(parser, c); + GET_CHAR (parser); + } + else if (c == QSE_T(']')) { + parser->token.type = QSE_STX_TOKEN_RBRACKET; + ADD_TOKEN_CHAR(parser, c); + GET_CHAR (parser); + } + else if (c == QSE_T('(')) { + parser->token.type = QSE_STX_TOKEN_LPAREN; + ADD_TOKEN_CHAR(parser, c); + GET_CHAR (parser); + } + else if (c == QSE_T(')')) { + parser->token.type = QSE_STX_TOKEN_RPAREN; + ADD_TOKEN_CHAR(parser, c); + GET_CHAR (parser); + } + else if (c == QSE_T('#')) { + /*ADD_TOKEN_CHAR(parser, c);*/ + GET_CHAR (parser); + + c = parser->curc; + if (c == QSE_T_EOF) { + parser->error_code = QSE_STX_PARSER_ERROR_LITERAL; + return -1; + } + else if (c == QSE_T('(')) { + ADD_TOKEN_CHAR(parser, c); + parser->token.type = QSE_STX_TOKEN_APAREN; + GET_CHAR (parser); + } + else if (c == QSE_T('\'')) { + GET_CHAR (parser); + if (__get_strlit(parser) == -1) return -1; + parser->token.type = QSE_STX_TOKEN_SYMLIT; + } + else if (!__is_closing_char(c) && !qse_isspace(c)) { + do { + ADD_TOKEN_CHAR(parser, c); + GET_CHAR (parser); + c = parser->curc; + } while (!__is_closing_char(c) && !qse_isspace(c)); + + parser->token.type = QSE_STX_TOKEN_SYMLIT; + } + else { + parser->error_code = QSE_STX_PARSER_ERROR_LITERAL; + return -1; + } + } + else if (c == QSE_T('.')) { + parser->token.type = QSE_STX_TOKEN_PERIOD; + ADD_TOKEN_CHAR(parser, c); + GET_CHAR (parser); + } + else if (c == QSE_T(';')) { + parser->token.type = QSE_STX_TOKEN_SEMICOLON; + ADD_TOKEN_CHAR(parser, c); + GET_CHAR (parser); + } + else if (__is_binary_char(c)) { + if (__get_binary(parser) == -1) return -1; + } + else { + parser->error_code = QSE_STX_PARSER_ERROR_CHAR; + return -1; + } + +//qse_printf (QSE_T("TOKEN: %s\n"), parser->token.name.buffer); + return 0; +} + +static int __get_ident (qse_stx_parser_t* parser) +{ + /* + * identifier ::= letter (letter | digit)* + * keyword ::= identifier ':' + */ + + qse_cint_t c = parser->curc; + parser->token.type = QSE_STX_TOKEN_IDENT; + + do { + ADD_TOKEN_CHAR(parser, c); + GET_CHAR (parser); + c = parser->curc; + } while (qse_isalnum(c)); + + if (c == QSE_T(':')) { + ADD_TOKEN_CHAR (parser, c); + parser->token.type = QSE_STX_TOKEN_KEYWORD; + GET_CHAR (parser); + } + + return 0; +} + +static int __get_numlit (qse_stx_parser_t* parser, qse_bool_t negated) +{ + /* + * ::= ['-'] + * ::= integer | float | scaledDecimal + * integer ::= decimalInteger | radixInteger + * decimalInteger ::= digits + * digits ::= digit+ + * radixInteger ::= radixSpecifier 'r' radixDigits + * radixSpecifier := digits + * radixDigits ::= (digit | uppercaseAlphabetic)+ + * float ::= mantissa [exponentLetter exponent] + * mantissa ::= digits'.' digits + * exponent ::= ['-']decimalInteger + * exponentLetter ::= 'e' | 'd' | 'q' + * scaledDecimal ::= scaledMantissa 's' [fractionalDigits] + * scaledMantissa ::= decimalInteger | mantissa + * fractionalDigits ::= decimalInteger + */ + + qse_cint_t c = parser->curc; + parser->token.type = QSE_STX_TOKEN_NUMLIT; + + do { + ADD_TOKEN_CHAR(parser, c); + GET_CHAR (parser); + c = parser->curc; + } while (qse_isalnum(c)); + + /* TODO; more */ + return 0; +} + +static int __get_charlit (qse_stx_parser_t* parser) +{ + /* + * character_literal ::= '$' character + * character ::= "Any character in the implementation-defined character set" + */ + + qse_cint_t c = parser->curc; /* even a new-line or white space would be taken */ + if (c == QSE_T_EOF) { + parser->error_code = QSE_STX_PARSER_ERROR_CHARLIT; + return -1; + } + + parser->token.type = QSE_STX_TOKEN_CHARLIT; + ADD_TOKEN_CHAR(parser, c); + GET_CHAR (parser); + return 0; +} + +static int __get_strlit (qse_stx_parser_t* parser) +{ + /* + * string_literal ::= stringDelimiter stringBody stringDelimiter + * stringBody ::= (nonStringDelimiter | (stringDelimiter stringDelimiter)*) + * stringDelimiter ::= ''' "a single quote" + */ + + /* TODO: C-like string */ + + qse_cint_t c = parser->curc; + parser->token.type = QSE_STX_TOKEN_STRLIT; + + do { + do { + ADD_TOKEN_CHAR (parser, c); + GET_CHAR (parser); + c = parser->curc; + + if (c == QSE_T_EOF) { + parser->error_code = QSE_STX_PARSER_ERROR_STRLIT; + return -1; + } + } while (c != QSE_T('\'')); + + GET_CHAR (parser); + c = parser->curc; + } while (c == QSE_T('\'')); + + return 0; +} + +static int __get_binary (qse_stx_parser_t* parser) +{ + /* + * binarySelector ::= binaryCharacter+ + */ + + qse_cint_t c = parser->curc; + ADD_TOKEN_CHAR (parser, c); + + if (c == QSE_T('-')) { + GET_CHAR (parser); + c = parser->curc; + if (qse_isdigit(c)) return __get_numlit(parser,qse_true); + } + else { + GET_CHAR (parser); + c = parser->curc; + } + + /* up to 2 characters only */ + if (__is_binary_char(c)) { + ADD_TOKEN_CHAR (parser, c); + GET_CHAR (parser); + c = parser->curc; + } + + /* or up to any occurrences */ + /* + while (__is_binary_char(c)) { + ADD_TOKEN_CHAR (parser, c); + GET_CHAR (parser); + c = parser->curc; + } + */ + + parser->token.type = QSE_STX_TOKEN_BINARY; + return 0; +} + +static int __skip_spaces (qse_stx_parser_t* parser) +{ + while (qse_isspace(parser->curc)) GET_CHAR (parser); + return 0; +} + +static int __skip_comment (qse_stx_parser_t* parser) +{ + while (parser->curc != QSE_T('"')) GET_CHAR (parser); + GET_CHAR (parser); + return 0; +} + +static int __get_char (qse_stx_parser_t* parser) +{ + qse_cint_t c; + + if (parser->ungotc_count > 0) { + parser->curc = parser->ungotc[parser->ungotc_count--]; + } + else { + if (parser->input_func ( + QSE_STX_PARSER_INPUT_CONSUME, + parser->input_owner, (void*)&c) == -1) { + parser->error_code = QSE_STX_PARSER_ERROR_INPUT; + return -1; + } + parser->curc = c; + } + return 0; +} + +static int __unget_char (qse_stx_parser_t* parser, qse_cint_t c) +{ + if (parser->ungotc_count >= qse_countof(parser->ungotc)) return -1; + parser->ungotc[parser->ungotc_count++] = c; + return 0; +} + +static int __open_input (qse_stx_parser_t* parser, void* input) +{ + if (parser->input_func( + QSE_STX_PARSER_INPUT_OPEN, + (void*)&parser->input_owner, input) == -1) { + parser->error_code = QSE_STX_PARSER_ERROR_INPUT; + return -1; + } + + parser->error_code = QSE_STX_PARSER_ERROR_NONE; + parser->curc = QSE_T_EOF; + parser->ungotc_count = 0; + return 0; +} + +static int __close_input (qse_stx_parser_t* parser) +{ + if (parser->input_func( + QSE_STX_PARSER_INPUT_CLOSE, + parser->input_owner, QSE_NULL) == -1) { + parser->error_code = QSE_STX_PARSER_ERROR_INPUT; + return -1; + } + + return 0; +} + diff --git a/qse/lib/stx/par.h b/qse/lib/stx/par.h new file mode 100644 index 00000000..d0de7e05 --- /dev/null +++ b/qse/lib/stx/par.h @@ -0,0 +1,107 @@ +/* + * $Id: parser.h 118 2008-03-03 11:21:33Z baconevi $ + */ + +#ifndef _QSE_STX_PARSER_H_ +#define _QSE_STX_PARSER_H_ + +#include +#include +#include +#include + +enum +{ + QSE_STX_PARSER_ERROR_NONE, + + /* system errors */ + QSE_STX_PARSER_ERROR_INPUT_FUNC, + QSE_STX_PARSER_ERROR_INPUT, + QSE_STX_PARSER_ERROR_MEMORY, + + /* lexical errors */ + QSE_STX_PARSER_ERROR_CHAR, + QSE_STX_PARSER_ERROR_CHARLIT, + QSE_STX_PARSER_ERROR_STRLIT, + QSE_STX_PARSER_ERROR_LITERAL, + + /* syntatic error */ + QSE_STX_PARSER_ERROR_MESSAGE_SELECTOR, + QSE_STX_PARSER_ERROR_ARGUMENT_NAME, + QSE_STX_PARSER_ERROR_TOO_MANY_ARGUMENTS, + + QSE_STX_PARSER_ERROR_PRIMITIVE_KEYWORD, + QSE_STX_PARSER_ERROR_PRIMITIVE_NUMBER, + QSE_STX_PARSER_ERROR_PRIMITIVE_NUMBER_RANGE, + QSE_STX_PARSER_ERROR_PRIMITIVE_NOT_CLOSED, + + QSE_STX_PARSER_ERROR_TEMPORARIES_NOT_CLOSED, + QSE_STX_PARSER_ERROR_TOO_MANY_TEMPORARIES, + QSE_STX_PARSER_ERROR_PSEUDO_VARIABLE, + QSE_STX_PARSER_ERROR_PRIMARY, + + QSE_STX_PARSER_ERROR_NO_PERIOD, + QSE_STX_PARSER_ERROR_NO_RPAREN, + QSE_STX_PARSER_ERROR_BLOCK_ARGUMENT_NAME, + QSE_STX_PARSER_ERROR_BLOCK_ARGUMENT_LIST, + QSE_STX_PARSER_ERROR_BLOCK_NOT_CLOSED, + + QSE_STX_PARSER_ERROR_UNDECLARED_NAME, + QSE_STX_PARSER_ERROR_TOO_MANY_LITERALS +}; + +enum +{ + /* input_func cmd */ + QSE_STX_PARSER_INPUT_OPEN, + QSE_STX_PARSER_INPUT_CLOSE, + QSE_STX_PARSER_INPUT_CONSUME, + QSE_STX_PARSER_INPUT_REWIND +}; + +typedef struct qse_stx_parser_t qse_stx_parser_t; + +struct qse_stx_parser_t +{ + qse_stx_t* stx; + int error_code; + + qse_word_t method_class; + qse_stx_name_t method_name; + + qse_char_t* temporaries[256]; /* TODO: different size? or dynamic? */ + qse_word_t argument_count; + qse_word_t temporary_count; + + qse_word_t literals[256]; /* TODO: make it a dynamic array */ + qse_word_t literal_count; + + qse_arr_t bytecode; + + qse_stx_token_t token; + qse_cint_t curc; + qse_cint_t ungotc[5]; + qse_size_t ungotc_count; + + void* input_owner; + int (*input_func) (int cmd, void* owner, void* arg); + + qse_bool_t __dynamic; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +qse_stx_parser_t* qse_stx_parser_open (qse_stx_parser_t* parser, qse_stx_t* stx); +void qse_stx_parser_close (qse_stx_parser_t* parser); + +const qse_char_t* qse_stx_parser_error_string (qse_stx_parser_t* parser); +int qse_stx_parser_parse_method ( + qse_stx_parser_t* parser, qse_word_t method_class, void* input); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/qse/lib/stx/stx.h b/qse/lib/stx/stx.h index afafbbdf..79d12a75 100644 --- a/qse/lib/stx/stx.h +++ b/qse/lib/stx/stx.h @@ -131,6 +131,7 @@ struct qse_stx_t qse_word_t class_systemdictionary; qse_word_t class_method; qse_word_t class_smallinteger; + qse_word_t class_parser; } ref; qse_bool_t __wantabort; /* TODO: make it a function pointer */