initial import
This commit is contained in:
18
qse/lib/stx/array.c
Normal file
18
qse/lib/stx/array.c
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* $Id: array.c 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#include <qse/stx/array.h>
|
||||
#include <qse/stx/object.h>
|
||||
#include <qse/bas/assert.h>
|
||||
|
||||
qse_word_t qse_stx_new_array (qse_stx_t* stx, qse_word_t size)
|
||||
{
|
||||
qse_word_t x;
|
||||
|
||||
qse_assert (stx->class_array != stx->nil);
|
||||
x = qse_stx_alloc_word_object (stx, QSE_NULL, 0, QSE_NULL, size);
|
||||
QSE_STX_CLASS(stx,x) = stx->class_array;
|
||||
|
||||
return x;
|
||||
}
|
21
qse/lib/stx/array.h
Normal file
21
qse/lib/stx/array.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* $Id: array.h 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#ifndef _QSE_STX_ARRAY_H_
|
||||
#define _QSE_STX_ARRAY_H_
|
||||
|
||||
#include <qse/stx/stx.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
qse_word_t qse_stx_new_array (qse_stx_t* stx, qse_word_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
676
qse/lib/stx/bootstrp.c
Normal file
676
qse/lib/stx/bootstrp.c
Normal file
@ -0,0 +1,676 @@
|
||||
/*
|
||||
* $Id: bootstrp.c 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#include <qse/stx/bootstrp.h>
|
||||
#include <qse/stx/symbol.h>
|
||||
#include <qse/stx/class.h>
|
||||
#include <qse/stx/object.h>
|
||||
#include <qse/stx/dict.h>
|
||||
#include <qse/stx/misc.h>
|
||||
|
||||
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->nil = qse_stx_alloc_word_object (stx, QSE_NULL, 0, QSE_NULL, 0);
|
||||
stx->true = qse_stx_alloc_word_object (stx, QSE_NULL, 0, QSE_NULL, 0);
|
||||
stx->false = qse_stx_alloc_word_object (stx, QSE_NULL, 0, QSE_NULL, 0);
|
||||
|
||||
qse_assert (stx->nil == QSE_STX_NIL);
|
||||
qse_assert (stx->true == QSE_STX_TRUE);
|
||||
qse_assert (stx->false == QSE_STX_FALSE);
|
||||
|
||||
/* 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_OBJECT(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_OBJECT(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_OBJECT(stx,superclass);
|
||||
nfields +=
|
||||
QSE_STX_FROM_SMALLINT(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_OBJECT(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_OBJECT(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_OBJECT(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: */
|
||||
}
|
||||
}
|
||||
|
21
qse/lib/stx/bootstrp.h
Normal file
21
qse/lib/stx/bootstrp.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* $Id: bootstrp.h 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#ifndef _QSE_STX_BOOTSTRP_H_
|
||||
#define _QSE_STX_BOOTSTRP_H_
|
||||
|
||||
#include <qse/stx/stx.h>
|
||||
|
||||
#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
|
193
qse/lib/stx/bytecode.c
Normal file
193
qse/lib/stx/bytecode.c
Normal file
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* $Id: bytecode.c 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
#include <qse/stx/bytecode.h>
|
||||
#include <qse/stx/class.h>
|
||||
#include <qse/stx/method.h>
|
||||
#include <qse/stx/dict.h>
|
||||
|
||||
static void __decode1 (qse_stx_t* stx, qse_word_t idx, void* data);
|
||||
static int __decode2 (qse_stx_t* stx,
|
||||
qse_stx_class_t* class_obj, qse_stx_method_t* method_obj);
|
||||
|
||||
int qse_stx_decode (qse_stx_t* stx, qse_word_t class)
|
||||
{
|
||||
qse_stx_class_t* class_obj;
|
||||
|
||||
class_obj = (qse_stx_class_t*)QSE_STX_OBJECT(stx, class);
|
||||
if (class_obj->methods == stx->nil) return 0;
|
||||
|
||||
/* TODO */
|
||||
qse_stx_dict_traverse (stx, class_obj->methods, __decode1, class_obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <qse/bas/stdio.h>
|
||||
static void __dump_object (qse_stx_t* stx, qse_word_t obj)
|
||||
{
|
||||
if (QSE_STX_IS_SMALLINT(obj)) {
|
||||
qse_printf (QSE_T("%d"), QSE_STX_FROM_SMALLINT(obj));
|
||||
}
|
||||
else if (QSE_STX_CLASS(stx,obj) == stx->class_character) {
|
||||
qse_printf (QSE_T("$%c"), QSE_STX_WORD_AT(stx,obj,0));
|
||||
}
|
||||
else if (QSE_STX_CLASS(stx,obj) == stx->class_string) {
|
||||
qse_printf (QSE_T("'%s'"), QSE_STX_DATA(stx,obj));
|
||||
}
|
||||
else if (QSE_STX_CLASS(stx,obj) == stx->class_symbol) {
|
||||
qse_printf (QSE_T("#%s"), QSE_STX_DATA(stx,obj));
|
||||
}
|
||||
else if (QSE_STX_IS_CHAR_OBJECT(stx, obj)) {
|
||||
qse_printf (QSE_T("unknow char object [%s]"), QSE_STX_DATA(stx,obj));
|
||||
}
|
||||
else if (QSE_STX_IS_BYTE_OBJECT(stx, obj)) {
|
||||
qse_printf (QSE_T("unknown byte object"), QSE_STX_DATA(stx,obj));
|
||||
}
|
||||
else if (QSE_STX_IS_WORD_OBJECT(stx, obj)) {
|
||||
qse_printf (QSE_T("unknown word object"), QSE_STX_DATA(stx,obj));
|
||||
}
|
||||
else {
|
||||
qse_printf (QSE_T("invalid object type"));
|
||||
}
|
||||
}
|
||||
|
||||
static void __decode1 (qse_stx_t* stx, qse_word_t idx, void* data)
|
||||
{
|
||||
qse_stx_method_t* method_obj;
|
||||
qse_stx_class_t* class_obj;
|
||||
qse_word_t key = QSE_STX_WORD_AT(stx,idx,QSE_STX_ASSOCIATION_KEY);
|
||||
qse_word_t value = QSE_STX_WORD_AT(stx,idx,QSE_STX_ASSOCIATION_VALUE);
|
||||
qse_word_t* literals;
|
||||
qse_word_t literal_count, i;
|
||||
|
||||
qse_word_t method_class;
|
||||
qse_stx_class_t* method_class_obj;
|
||||
|
||||
class_obj = (qse_stx_class_t*)data;
|
||||
|
||||
qse_printf (QSE_T("* Method: %s\n"), QSE_STX_DATA(stx, key));
|
||||
method_obj = (qse_stx_method_t*)QSE_STX_OBJECT(stx, value);
|
||||
|
||||
literals = method_obj->literals;
|
||||
/*
|
||||
literal_count = QSE_STX_SIZE(stx, value) -
|
||||
(QSE_STX_FROM_SMALLINT(class_obj->spec) >> QSE_STX_SPEC_INDEXABLE_BITS);
|
||||
*/
|
||||
method_class = QSE_STX_CLASS(stx,value);
|
||||
method_class_obj = QSE_STX_OBJECT(stx, method_class);
|
||||
literal_count = QSE_STX_SIZE(stx,value) -
|
||||
(QSE_STX_FROM_SMALLINT(method_class_obj->spec) >> QSE_STX_SPEC_INDEXABLE_BITS);
|
||||
|
||||
qse_printf (QSE_T("* Literal Count: %d, Temporary Count: %d, Argument Count: %d\n"),
|
||||
literal_count,
|
||||
QSE_STX_FROM_SMALLINT(method_obj->tmpcount),
|
||||
QSE_STX_FROM_SMALLINT(method_obj->argcount));
|
||||
for (i = 0; i < literal_count; i++) {
|
||||
qse_printf (QSE_T("%d. ["), i);
|
||||
__dump_object (stx, literals[i]);
|
||||
qse_printf (QSE_T("]\n"));
|
||||
}
|
||||
__decode2 (stx, data, method_obj);
|
||||
}
|
||||
|
||||
static int __decode2 (qse_stx_t* stx,
|
||||
qse_stx_class_t* class_obj, qse_stx_method_t* method_obj)
|
||||
{
|
||||
qse_stx_byte_object_t* bytecodes;
|
||||
qse_word_t bytecode_size, pc = 0;
|
||||
int code, next, next2;
|
||||
|
||||
static const qse_char_t* stack_opcode_names[] =
|
||||
{
|
||||
QSE_T("push_receiver_variable"),
|
||||
QSE_T("push_temporary_location"),
|
||||
QSE_T("push_literal_constant"),
|
||||
QSE_T("push_literal_variable"),
|
||||
QSE_T("store_receiver_variable"),
|
||||
QSE_T("store_temporary_location")
|
||||
};
|
||||
|
||||
static const qse_char_t* send_opcode_names[] =
|
||||
{
|
||||
QSE_T("send_to_self"),
|
||||
QSE_T("send_to_super")
|
||||
};
|
||||
|
||||
static const qse_char_t* stack_special_opcode_names[] =
|
||||
{
|
||||
QSE_T("pop_stack_top"),
|
||||
QSE_T("duplicate_pop_stack_top"),
|
||||
QSE_T("push_active_context"),
|
||||
QSE_T("push_nil"),
|
||||
QSE_T("push_true"),
|
||||
QSE_T("push_false"),
|
||||
QSE_T("push_receiver")
|
||||
};
|
||||
|
||||
static const qse_char_t* return_opcode_names[] =
|
||||
{
|
||||
QSE_T("return_receiver"),
|
||||
QSE_T("return_true"),
|
||||
QSE_T("return_false"),
|
||||
QSE_T("return_nil"),
|
||||
QSE_T("return_from_message"),
|
||||
QSE_T("return_from_block")
|
||||
};
|
||||
|
||||
bytecodes = QSE_STX_BYTE_OBJECT(stx, method_obj->bytecodes);
|
||||
bytecode_size = QSE_STX_SIZE(stx, method_obj->bytecodes);
|
||||
|
||||
while (pc < bytecode_size) {
|
||||
code = bytecodes->data[pc++];
|
||||
|
||||
if (code >= 0x00 && code <= 0x5F) {
|
||||
/* stack */
|
||||
qse_printf (QSE_T("%s %d\n"),
|
||||
stack_opcode_names[code >> 4], code & 0x0F);
|
||||
}
|
||||
else if (code >= 0x60 && code <= 0x65) {
|
||||
/* stack extended */
|
||||
next = bytecodes->data[pc++];
|
||||
qse_printf (QSE_T("%s %d\n"),
|
||||
stack_opcode_names[code & 0x0F], next);
|
||||
}
|
||||
else if (code >= 0x67 && code <= 0x6D) {
|
||||
/* stack special */
|
||||
qse_printf (QSE_T("%s\n"),
|
||||
stack_special_opcode_names[code - 0x67]);
|
||||
}
|
||||
|
||||
else if (code >= 0x70 && code <= 0x71 ) {
|
||||
/* send message */
|
||||
next = bytecodes->data[pc++];
|
||||
qse_printf (QSE_T("%s nargs(%d) selector(%d)\n"),
|
||||
send_opcode_names[code - 0x70], next >> 5, next & 0x1F);
|
||||
}
|
||||
else if (code >= 0x72 && code <= 0x73 ) {
|
||||
/* send message extended */
|
||||
next = bytecodes->data[pc++];
|
||||
next2 = bytecodes->data[pc++];
|
||||
qse_printf (QSE_T("%s %d %d\n"),
|
||||
send_opcode_names[code - 0x72], next, next2);
|
||||
|
||||
}
|
||||
else if (code >= 0x78 && code <= 0x7D) {
|
||||
qse_printf (QSE_T("%s\n"),
|
||||
return_opcode_names[code - 0x78]);
|
||||
}
|
||||
else if (code >= 0x80 && code <= 0x8F) {
|
||||
// jump
|
||||
}
|
||||
else if (code >= 0xF0 && code <= 0xFF) {
|
||||
// primitive
|
||||
next = bytecodes->data[pc++];
|
||||
qse_printf (QSE_T("do_primitive %d\n"), ((code & 0x0F) << 8) | next);
|
||||
|
||||
}
|
||||
else {
|
||||
qse_printf (QSE_T("unknown byte code 0x%x\n"), code);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
56
qse/lib/stx/bytecode.h
Normal file
56
qse/lib/stx/bytecode.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* $Id: bytecode.h 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#ifndef _QSE_STX_BYTECODE_H_
|
||||
#define _QSE_STX_BYTECODE_H_
|
||||
|
||||
#include <qse/stx/stx.h>
|
||||
|
||||
#define PUSH_RECEIVER_VARIABLE 0x00
|
||||
#define PUSH_TEMPORARY_LOCATION 0x10
|
||||
#define PUSH_LITERAL_CONSTANT 0x20
|
||||
#define PUSH_LITERAL_VARIABLE 0x30
|
||||
#define STORE_RECEIVER_VARIABLE 0x40
|
||||
#define STORE_TEMPORARY_LOCATION 0x50
|
||||
|
||||
#define PUSH_RECEIVER_VARIABLE_EXTENDED 0x60
|
||||
#define PUSH_TEMPORARY_LOCATION_EXTENDED 0x61
|
||||
#define PUSH_LITERAL_CONSTANT_EXTENDED 0x62
|
||||
#define PUSH_LITERAL_VARIABLE_EXTENDED 0x63
|
||||
#define STORE_RECEIVER_VARIABLE_EXTENDED 0x64
|
||||
#define STORE_TEMPORARY_LOCATION_EXTENDED 0x65
|
||||
|
||||
#define POP_STACK_TOP 0x67
|
||||
#define DUPLICATE_POP_STACK_TOP 0x68
|
||||
#define PUSH_ACTIVE_CONTEXT 0x69
|
||||
#define PUSH_NIL 0x6A
|
||||
#define PUSH_TRUE 0x6B
|
||||
#define PUSH_FALSE 0x6C
|
||||
#define PUSH_RECEIVER 0x6D
|
||||
|
||||
#define SEND_TO_SELF 0x70
|
||||
#define SEND_TO_SUPER 0x71
|
||||
#define SEND_TO_SELF_EXTENDED 0x72
|
||||
#define SEND_TO_SUPER_EXTENDED 0x73
|
||||
|
||||
#define RETURN_RECEIVER 0x78
|
||||
#define RETURN_TRUE 0x79
|
||||
#define RETURN_FALSE 0x7A
|
||||
#define RETURN_NIL 0x7B
|
||||
#define RETURN_FROM_MESSAGE 0x7C
|
||||
#define RETURN_FROM_BLOCK 0x7D
|
||||
|
||||
#define DO_PRIMITIVE 0xF0
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int qse_stx_decode (qse_stx_t* stx, qse_word_t class_idx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
168
qse/lib/stx/class.c
Normal file
168
qse/lib/stx/class.c
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* $Id: class.c 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#include <qse/stx/class.h>
|
||||
#include <qse/stx/symbol.h>
|
||||
#include <qse/stx/object.h>
|
||||
#include <qse/stx/dict.h>
|
||||
#include <qse/stx/misc.h>
|
||||
|
||||
qse_word_t qse_stx_new_class (qse_stx_t* stx, const qse_char_t* name)
|
||||
{
|
||||
qse_word_t meta, class;
|
||||
qse_word_t class_name;
|
||||
|
||||
meta = qse_stx_alloc_word_object (
|
||||
stx, QSE_NULL, QSE_STX_METACLASS_SIZE, QSE_NULL, 0);
|
||||
QSE_STX_CLASS(stx,meta) = stx->class_metaclass;
|
||||
/* the spec of the metaclass must be the spec of its
|
||||
* instance. so the QSE_STX_CLASS_SIZE is set */
|
||||
QSE_STX_WORD_AT(stx,meta,QSE_STX_METACLASS_SPEC) =
|
||||
QSE_STX_TO_SMALLINT((QSE_STX_CLASS_SIZE << QSE_STX_SPEC_INDEXABLE_BITS) | QSE_STX_SPEC_NOT_INDEXABLE);
|
||||
|
||||
/* the spec of the class is set later in __create_builtin_classes */
|
||||
class = qse_stx_alloc_word_object (
|
||||
stx, QSE_NULL, QSE_STX_CLASS_SIZE, QSE_NULL, 0);
|
||||
QSE_STX_CLASS(stx,class) = meta;
|
||||
class_name = qse_stx_new_symbol (stx, name);
|
||||
QSE_STX_WORD_AT(stx,class,QSE_STX_CLASS_NAME) = class_name;
|
||||
|
||||
qse_stx_dict_put (stx, stx->smalltalk, class_name, class);
|
||||
return class;
|
||||
}
|
||||
|
||||
qse_word_t qse_stx_lookup_class (qse_stx_t* stx, const qse_char_t* name)
|
||||
{
|
||||
qse_word_t assoc, meta, value;
|
||||
|
||||
assoc = qse_stx_dict_lookup (stx, stx->smalltalk, name);
|
||||
if (assoc == stx->nil) {
|
||||
return stx->nil;
|
||||
}
|
||||
|
||||
value = QSE_STX_WORD_AT(stx,assoc,QSE_STX_ASSOCIATION_VALUE);
|
||||
meta = QSE_STX_CLASS(stx,value);
|
||||
if (QSE_STX_CLASS(stx,meta) != stx->class_metaclass) return stx->nil;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int qse_stx_get_instance_variable_index (
|
||||
qse_stx_t* stx, qse_word_t class_index,
|
||||
const qse_char_t* name, qse_word_t* index)
|
||||
{
|
||||
qse_word_t index_super = 0;
|
||||
qse_stx_class_t* class_obj;
|
||||
qse_stx_char_object_t* string;
|
||||
|
||||
class_obj = (qse_stx_class_t*)QSE_STX_OBJECT(stx, class_index);
|
||||
qse_assert (class_obj != QSE_NULL);
|
||||
|
||||
if (class_obj->superclass != stx->nil) {
|
||||
if (qse_stx_get_instance_variable_index (
|
||||
stx, class_obj->superclass, name, &index_super) == 0) {
|
||||
*index = index_super;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (class_obj->header.class == stx->class_metaclass) {
|
||||
/* metaclass */
|
||||
/* TODO: can a metaclas have instance variables? */
|
||||
*index = index_super;
|
||||
}
|
||||
else {
|
||||
if (class_obj->variables == stx->nil) *index = 0;
|
||||
else {
|
||||
string = QSE_STX_CHAR_OBJECT(stx, class_obj->variables);
|
||||
if (qse_stx_strword(string->data, name, index) != QSE_NULL) {
|
||||
*index += index_super;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
*index += index_super;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
qse_word_t qse_stx_lookup_class_variable (
|
||||
qse_stx_t* stx, qse_word_t class_index, const qse_char_t* name)
|
||||
{
|
||||
qse_stx_class_t* class_obj;
|
||||
|
||||
class_obj = (qse_stx_class_t*)QSE_STX_OBJECT(stx, class_index);
|
||||
qse_assert (class_obj != QSE_NULL);
|
||||
|
||||
if (class_obj->superclass != stx->nil) {
|
||||
qse_word_t tmp;
|
||||
tmp = qse_stx_lookup_class_variable (
|
||||
stx, class_obj->superclass, name);
|
||||
if (tmp != stx->nil) return tmp;
|
||||
}
|
||||
|
||||
/* TODO: can a metaclas have class variables? */
|
||||
if (class_obj->header.class != stx->class_metaclass &&
|
||||
class_obj->class_variables != stx->nil) {
|
||||
if (qse_stx_dict_lookup(stx,
|
||||
class_obj->class_variables,name) != stx->nil) return class_index;
|
||||
}
|
||||
|
||||
return stx->nil;
|
||||
}
|
||||
|
||||
qse_word_t qse_stx_lookup_method (qse_stx_t* stx,
|
||||
qse_word_t class_index, const qse_char_t* name, qse_bool_t from_super)
|
||||
{
|
||||
qse_stx_class_t* class_obj;
|
||||
|
||||
class_obj = (qse_stx_class_t*)QSE_STX_OBJECT(stx, class_index);
|
||||
qse_assert (class_obj != QSE_NULL);
|
||||
|
||||
#if 0
|
||||
if (class_obj->header.class != stx->class_metaclass &&
|
||||
class_obj->methods != stx->nil) {
|
||||
qse_word_t assoc;
|
||||
assoc = qse_stx_dict_lookup(stx, class_obj->methods, name);
|
||||
if (assoc != stx->nil) {
|
||||
qse_assert (QSE_STX_CLASS(stx,assoc) == stx->class_association);
|
||||
return QSE_STX_WORD_AT(stx, assoc, QSE_STX_ASSOCIATION_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
if (class_obj->superclass != stx->nil) {
|
||||
qse_word_t tmp;
|
||||
tmp = qse_stx_lookup_method (
|
||||
stx, class_obj->superclass, name);
|
||||
if (tmp != stx->nil) return tmp;
|
||||
}
|
||||
#endif
|
||||
|
||||
while (class_index != stx->nil) {
|
||||
class_obj = (qse_stx_class_t*)QSE_STX_OBJECT(stx, class_index);
|
||||
|
||||
qse_assert (class_obj != QSE_NULL);
|
||||
qse_assert (
|
||||
class_obj->header.class == stx->class_metaclass ||
|
||||
QSE_STX_CLASS(stx,class_obj->header.class) == stx->class_metaclass);
|
||||
|
||||
if (from_super) {
|
||||
from_super = qse_false;
|
||||
}
|
||||
else if (class_obj->methods != stx->nil) {
|
||||
qse_word_t assoc;
|
||||
assoc = qse_stx_dict_lookup(stx, class_obj->methods, name);
|
||||
if (assoc != stx->nil) {
|
||||
qse_assert (QSE_STX_CLASS(stx,assoc) == stx->class_association);
|
||||
return QSE_STX_WORD_AT(stx, assoc, QSE_STX_ASSOCIATION_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
class_index = class_obj->superclass;
|
||||
}
|
||||
|
||||
return stx->nil;
|
||||
}
|
||||
|
81
qse/lib/stx/class.h
Normal file
81
qse/lib/stx/class.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* $Id: class.h 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#ifndef _QSE_STX_CLASS_H_
|
||||
#define _QSE_STX_CLASS_H_
|
||||
|
||||
#include <qse/stx/stx.h>
|
||||
|
||||
/* definitions for common objects */
|
||||
#define QSE_STX_CLASS_SIZE 8
|
||||
#define QSE_STX_CLASS_SPEC 0
|
||||
#define QSE_STX_CLASS_METHODS 1
|
||||
#define QSE_STX_CLASS_SUPERCLASS 2
|
||||
#define QSE_STX_CLASS_SUBCLASSES 3
|
||||
#define QSE_STX_CLASS_NAME 4
|
||||
#define QSE_STX_CLASS_VARIABLES 5
|
||||
#define QSE_STX_CLASS_CLASS_VARIABLES 6
|
||||
#define QSE_STX_CLASS_POOL_DICTIONARIES 7
|
||||
|
||||
#define QSE_STX_METACLASS_SIZE 5
|
||||
#define QSE_STX_METACLASS_SPEC 0
|
||||
#define QSE_STX_METACLASS_METHODS 1
|
||||
#define QSE_STX_METACLASS_SUPERCLASS 2
|
||||
#define QSE_STX_METACLASS_SUBCLASSES 3
|
||||
#define QSE_STX_METACLASS_INSTANCE_CLASS 4
|
||||
|
||||
#define QSE_STX_SPEC_INDEXABLE_BITS 2
|
||||
#define QSE_STX_SPEC_INDEXABLE_MASK 3
|
||||
#define QSE_STX_SPEC_NOT_INDEXABLE 0
|
||||
#define QSE_STX_SPEC_WORD_INDEXABLE 1
|
||||
#define QSE_STX_SPEC_BYTE_INDEXABLE 2
|
||||
#define QSE_STX_SPEC_CHAR_INDEXABLE 3
|
||||
|
||||
struct qse_stx_class_t
|
||||
{
|
||||
qse_stx_objhdr_t header;
|
||||
qse_word_t spec; /* indexable: 2, nfields: the rest */
|
||||
qse_word_t methods;
|
||||
qse_word_t superclass;
|
||||
qse_word_t subclasses;
|
||||
qse_word_t name;
|
||||
qse_word_t variables;
|
||||
qse_word_t class_variables;
|
||||
qse_word_t pool_dictonaries;
|
||||
};
|
||||
|
||||
struct qse_stx_metaclass_t
|
||||
{
|
||||
qse_stx_objhdr_t header;
|
||||
qse_word_t spec;
|
||||
qse_word_t methods;
|
||||
qse_word_t superclass;
|
||||
qse_word_t subclasses;
|
||||
qse_word_t instance_class;
|
||||
};
|
||||
|
||||
typedef struct qse_stx_class_t qse_stx_class_t;
|
||||
typedef struct qse_stx_metaclass_t qse_stx_metaclass_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
qse_word_t qse_stx_new_class (qse_stx_t* stx, const qse_char_t* name);
|
||||
qse_word_t qse_stx_lookup_class (qse_stx_t* stx, const qse_char_t* name);
|
||||
|
||||
int qse_stx_get_instance_variable_index (
|
||||
qse_stx_t* stx, qse_word_t class_index,
|
||||
const qse_char_t* name, qse_word_t* index);
|
||||
|
||||
qse_word_t qse_stx_lookup_class_variable (
|
||||
qse_stx_t* stx, qse_word_t class_index, const qse_char_t* name);
|
||||
qse_word_t qse_stx_lookup_method (qse_stx_t* stx,
|
||||
qse_word_t class_index, const qse_char_t* name, qse_bool_t from_super);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
75
qse/lib/stx/context.c
Normal file
75
qse/lib/stx/context.c
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* $Id: context.c 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#include <qse/stx/context.h>
|
||||
#include <qse/stx/object.h>
|
||||
#include <qse/stx/class.h>
|
||||
#include <qse/stx/misc.h>
|
||||
|
||||
qse_word_t qse_stx_new_context (qse_stx_t* stx,
|
||||
qse_word_t method, qse_word_t args, qse_word_t temp)
|
||||
{
|
||||
qse_word_t context;
|
||||
qse_stx_context_t* obj;
|
||||
|
||||
context = qse_stx_alloc_word_object(
|
||||
stx, QSE_NULL, QSE_STX_CONTEXT_SIZE, QSE_NULL, 0);
|
||||
obj = (qse_stx_context_t*)QSE_STX_OBJECT(stx,context);
|
||||
obj->header.class = qse_stx_lookup_class(stx,QSE_T("Context"));
|
||||
obj->ip = QSE_STX_TO_SMALLINT(0);
|
||||
obj->method = method;
|
||||
obj->arguments = args;
|
||||
obj->temporaries = temp;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
static qse_byte_t __fetch_byte (
|
||||
qse_stx_t* stx, qse_stx_context_t* context_obj)
|
||||
{
|
||||
qse_word_t ip, method;
|
||||
|
||||
qse_assert (QSE_STX_IS_SMALLINT(context_obj->ip));
|
||||
ip = QSE_STX_FROM_SMALLINT(context_obj->ip);
|
||||
method = context_obj->method;
|
||||
|
||||
/* increment instruction pointer */
|
||||
context_obj->ip = QSE_STX_TO_SMALLINT(ip + 1);
|
||||
|
||||
qse_assert (QSE_STX_TYPE(stx,method) == QSE_STX_BYTE_INDEXED);
|
||||
return QSE_STX_BYTE_AT(stx,method,ip);
|
||||
}
|
||||
|
||||
int qse_stx_run_context (qse_stx_t* stx, qse_word_t context)
|
||||
{
|
||||
qse_byte_t byte, operand;
|
||||
qse_stx_context_t* context_obj;
|
||||
|
||||
context_obj = (qse_stx_context_t*)QSE_STX_OBJECT(stx,context);
|
||||
|
||||
while (!stx->__wantabort) {
|
||||
/* check_process_switch (); // hopefully */
|
||||
byte = __fetch_byte (stx, context_obj);
|
||||
|
||||
#ifdef _DOS
|
||||
printf (QSE_T("code: %x\n"), byte);
|
||||
#else
|
||||
qse_printf (QSE_T("code: %x\n"), byte);
|
||||
#endif
|
||||
|
||||
switch (byte) {
|
||||
case PUSH_OBJECT:
|
||||
operand = __fetch_byte (stx, context_obj);
|
||||
break;
|
||||
case SEND_UNARY_MESSAGE:
|
||||
operand = __fetch_byte (stx, context_obj);
|
||||
break;
|
||||
case HALT:
|
||||
goto exit_run_context;
|
||||
}
|
||||
}
|
||||
|
||||
exit_run_context:
|
||||
return 0;
|
||||
}
|
43
qse/lib/stx/context.h
Normal file
43
qse/lib/stx/context.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* $Id: context.h 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#ifndef _QSE_STX_CONTEXT_H_
|
||||
#define _QSE_STX_CONTEXT_H_
|
||||
|
||||
#include <qse/stx/stx.h>
|
||||
|
||||
#define PUSH_OBJECT 0xA0
|
||||
#define SEND_UNARY_MESSAGE 0xB0
|
||||
#define HALT 0xFF
|
||||
|
||||
#define QSE_STX_CONTEXT_SIZE 4
|
||||
#define QSE_STX_CONTEXT_IP 0
|
||||
#define QSE_STX_CONTEXT_METHOD 1
|
||||
#define QSE_STX_CONTEXT_ARGUMENTS 2
|
||||
#define QSE_STX_CONTEXT_TEMPORARIES 3
|
||||
|
||||
struct qse_stx_context_t
|
||||
{
|
||||
qse_stx_objhdr_t header;
|
||||
qse_word_t ip;
|
||||
qse_word_t method;
|
||||
qse_word_t arguments;
|
||||
qse_word_t temporaries;
|
||||
};
|
||||
|
||||
typedef struct qse_stx_context_t qse_stx_context_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
qse_word_t qse_stx_new_context (qse_stx_t* stx,
|
||||
qse_word_t method, qse_word_t args, qse_word_t temp);
|
||||
int qse_stx_run_context (qse_stx_t* stx, qse_word_t context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
190
qse/lib/stx/dict.c
Normal file
190
qse/lib/stx/dict.c
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* $Id: dict.c 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#include <qse/stx/dict.h>
|
||||
#include <qse/stx/object.h>
|
||||
#include <qse/stx/misc.h>
|
||||
|
||||
/* NOTE:
|
||||
* The code here implements SystemDictionary whose key is always a symbol.
|
||||
* Dictionary, on the contrary, can accept any object as a key.
|
||||
*/
|
||||
|
||||
qse_word_t __new_association (
|
||||
qse_stx_t* stx, qse_word_t key, qse_word_t value)
|
||||
{
|
||||
qse_word_t x;
|
||||
#ifdef __GNUC__
|
||||
qse_word_t data[2] = { key, value };
|
||||
#else
|
||||
qse_word_t data[2];
|
||||
data[0] = key;
|
||||
data[1] = value;
|
||||
#endif
|
||||
x = qse_stx_alloc_word_object (
|
||||
stx, data, QSE_STX_ASSOCIATION_SIZE, QSE_NULL, 0);
|
||||
QSE_STX_CLASS(stx,x) = stx->class_association;
|
||||
return x;
|
||||
}
|
||||
|
||||
static qse_word_t __dict_find_slot (
|
||||
qse_stx_t* stx, qse_word_t dict, qse_word_t key)
|
||||
{
|
||||
qse_word_t size, hash, index, assoc, symbol;
|
||||
qse_stx_word_object_t* dict_obj;
|
||||
|
||||
qse_assert (!QSE_STX_IS_SMALLINT(dict) &&
|
||||
QSE_STX_IS_WORD_OBJECT(stx, dict));
|
||||
qse_assert (dict == stx->smalltalk ||
|
||||
qse_stx_classof(stx,dict) == stx->class_system_dictionary);
|
||||
qse_assert (qse_stx_classof(stx,key) == stx->class_symbol);
|
||||
|
||||
size = QSE_STX_SIZE(stx,dict);
|
||||
hash = qse_stx_hash_object(stx, key);
|
||||
|
||||
/* consider tally, the only instance variable of a system dictionary */
|
||||
index = hash % (size - 1) + 1;
|
||||
|
||||
dict_obj = QSE_STX_WORD_OBJECT(stx,dict);
|
||||
|
||||
while (1) {
|
||||
assoc = dict_obj->data[index];
|
||||
if (assoc == stx->nil) break;
|
||||
|
||||
symbol = QSE_STX_WORD_AT(stx,assoc,QSE_STX_ASSOCIATION_KEY);
|
||||
qse_assert (qse_stx_classof(stx,symbol) == stx->class_symbol);
|
||||
|
||||
/* NOTE:
|
||||
* shallow comparison is enough for identity check
|
||||
* because a symbol can just be a key of a system dictionary
|
||||
*/
|
||||
if (qse_strxncmp(
|
||||
QSE_STX_DATA(stx,key), QSE_STX_SIZE(stx,key),
|
||||
QSE_STX_DATA(stx,symbol), QSE_STX_SIZE(stx,symbol)) == 0) break;
|
||||
|
||||
/* consider tally here too */
|
||||
index = index % (size - 1) + 1;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static void __grow_dict (qse_stx_t* stx, qse_word_t dict)
|
||||
{
|
||||
qse_word_t new, size, index, assoc;
|
||||
|
||||
/* WARNING:
|
||||
* if this assertion fails, adjust the initial size of the
|
||||
* system dictionary. i don't want this function to be called
|
||||
* during the bootstrapping.
|
||||
*/
|
||||
qse_assert (stx->class_system_dictionary != stx->nil);
|
||||
qse_assert (qse_stx_classof(stx,dict) == stx->class_system_dictionary);
|
||||
|
||||
size = QSE_STX_SIZE(stx,dict);
|
||||
new = qse_stx_instantiate (stx,
|
||||
QSE_STX_CLASS(stx,dict), QSE_NULL, QSE_NULL, (size - 1) * 2);
|
||||
QSE_STX_WORD_AT(stx,new,0) = QSE_STX_TO_SMALLINT(0);
|
||||
|
||||
for (index = 1; index < size; index++) {
|
||||
assoc = QSE_STX_WORD_AT(stx,dict,index);
|
||||
if (assoc == stx->nil) continue;
|
||||
|
||||
qse_stx_dict_put (stx, new,
|
||||
QSE_STX_WORD_AT(stx,assoc,QSE_STX_ASSOCIATION_KEY),
|
||||
QSE_STX_WORD_AT(stx,assoc,QSE_STX_ASSOCIATION_VALUE));
|
||||
}
|
||||
|
||||
/* TODO: explore if dict can be immediately destroyed. */
|
||||
|
||||
qse_assert (qse_sizeof(qse_stx_object_t*) == qse_sizeof(qse_uint_t));
|
||||
QSE_SWAP (QSE_STX_OBJECT(stx,dict),
|
||||
QSE_STX_OBJECT(stx,new),
|
||||
qse_stx_object_t*, qse_uint_t);
|
||||
}
|
||||
|
||||
qse_word_t qse_stx_dict_lookup (
|
||||
qse_stx_t* stx, qse_word_t dict, const qse_char_t* key)
|
||||
{
|
||||
qse_word_t size, hash, index, assoc, symbol;
|
||||
qse_stx_word_object_t* dict_obj;
|
||||
|
||||
qse_assert (!QSE_STX_IS_SMALLINT(dict) &&
|
||||
QSE_STX_IS_WORD_OBJECT(stx, dict));
|
||||
qse_assert (dict == stx->smalltalk ||
|
||||
qse_stx_classof(stx,dict) == stx->class_system_dictionary);
|
||||
|
||||
size = QSE_STX_SIZE(stx,dict);
|
||||
hash = qse_stx_hash(key, qse_strlen(key) * qse_sizeof(qse_char_t));
|
||||
|
||||
/* consider tally, the only instance variable of a system dictionary */
|
||||
index = hash % (size - 1) + 1;
|
||||
|
||||
dict_obj = QSE_STX_WORD_OBJECT(stx,dict);
|
||||
|
||||
while (1) {
|
||||
assoc = dict_obj->data[index];
|
||||
if (assoc == stx->nil) break;
|
||||
|
||||
symbol = QSE_STX_WORD_AT(stx,assoc,QSE_STX_ASSOCIATION_KEY);
|
||||
qse_assert (qse_stx_classof(stx,symbol) == stx->class_symbol);
|
||||
|
||||
if (qse_strxcmp (QSE_STX_DATA(stx,symbol),
|
||||
QSE_STX_SIZE(stx,symbol), key) == 0) break;
|
||||
|
||||
/* consider tally here too */
|
||||
index = index % (size - 1) + 1;
|
||||
}
|
||||
|
||||
return QSE_STX_WORD_AT(stx,dict,index);
|
||||
}
|
||||
|
||||
qse_word_t qse_stx_dict_get (qse_stx_t* stx, qse_word_t dict, qse_word_t key)
|
||||
{
|
||||
return QSE_STX_WORD_AT(stx,dict,__dict_find_slot(stx, dict, key));
|
||||
}
|
||||
|
||||
qse_word_t qse_stx_dict_put (
|
||||
qse_stx_t* stx, qse_word_t dict, qse_word_t key, qse_word_t value)
|
||||
{
|
||||
qse_word_t slot, capa, tally, assoc;
|
||||
|
||||
/* the dictionary must have at least one slot excluding tally */
|
||||
qse_assert (QSE_STX_SIZE(stx,dict) > 1);
|
||||
|
||||
capa = QSE_STX_SIZE(stx,dict) - 1;
|
||||
tally = QSE_STX_FROM_SMALLINT(QSE_STX_WORD_AT(stx,dict,0));
|
||||
if (capa <= tally + 1) {
|
||||
__grow_dict (stx, dict);
|
||||
/* refresh tally */
|
||||
tally = QSE_STX_FROM_SMALLINT(QSE_STX_WORD_AT(stx,dict,0));
|
||||
}
|
||||
|
||||
slot = __dict_find_slot (stx, dict, key);
|
||||
|
||||
assoc = QSE_STX_WORD_AT(stx,dict,slot);
|
||||
if (assoc == stx->nil) {
|
||||
QSE_STX_WORD_AT(stx,dict,slot) =
|
||||
__new_association (stx, key, value);
|
||||
QSE_STX_WORD_AT(stx,dict,0) = QSE_STX_TO_SMALLINT(tally + 1);
|
||||
}
|
||||
else QSE_STX_WORD_AT(stx,assoc,QSE_STX_ASSOCIATION_VALUE) = value;
|
||||
|
||||
return QSE_STX_WORD_AT(stx,dict,slot);
|
||||
}
|
||||
|
||||
void qse_stx_dict_traverse (
|
||||
qse_stx_t* stx, qse_word_t dict,
|
||||
void (*func) (qse_stx_t*,qse_word_t,void*), void* data)
|
||||
{
|
||||
qse_word_t index, assoc;
|
||||
qse_word_t size = QSE_STX_SIZE(stx,dict);
|
||||
|
||||
for (index = 1; index < size; index++) {
|
||||
assoc = QSE_STX_WORD_AT(stx,dict,index);
|
||||
if (assoc == stx->nil) continue;
|
||||
func (stx, assoc, data);
|
||||
}
|
||||
}
|
||||
|
42
qse/lib/stx/dict.h
Normal file
42
qse/lib/stx/dict.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* $Id: dict.h 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#ifndef _QSE_STX_DICT_H_
|
||||
#define _QSE_STX_DICT_H_
|
||||
|
||||
#include <qse/stx/stx.h>
|
||||
|
||||
#define QSE_STX_ASSOCIATION_SIZE 2
|
||||
#define QSE_STX_ASSOCIATION_KEY 0
|
||||
#define QSE_STX_ASSOCIATION_VALUE 1
|
||||
|
||||
struct qse_stx_association_t
|
||||
{
|
||||
qse_stx_objhdr_t header;
|
||||
qse_word_t key;
|
||||
qse_word_t value;
|
||||
};
|
||||
|
||||
typedef struct qse_stx_association_t qse_stx_association_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
|
||||
qse_word_t qse_stx_dict_lookup (
|
||||
qse_stx_t* stx, qse_word_t dict, const qse_char_t* key);
|
||||
qse_word_t qse_stx_dict_get (
|
||||
qse_stx_t* stx, qse_word_t dict, qse_word_t key);
|
||||
qse_word_t qse_stx_dict_put (
|
||||
qse_stx_t* stx, qse_word_t dict, qse_word_t key, qse_word_t value);
|
||||
void qse_stx_dict_traverse (
|
||||
qse_stx_t* stx, qse_word_t dict,
|
||||
void (*func) (qse_stx_t*,qse_word_t,void*), void* data);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
380
qse/lib/stx/interp.c
Normal file
380
qse/lib/stx/interp.c
Normal file
@ -0,0 +1,380 @@
|
||||
/*
|
||||
* $Id: interp.c 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#include <qse/stx/interp.h>
|
||||
#include <qse/stx/method.h>
|
||||
#include <qse/stx/object.h>
|
||||
#include <qse/stx/array.h>
|
||||
#include <qse/stx/class.h>
|
||||
#include <qse/bas/assert.h>
|
||||
#include <qse/bas/memory.h>
|
||||
|
||||
/*
|
||||
activation record
|
||||
|
||||
....
|
||||
....
|
||||
....
|
||||
-------------------
|
||||
previous stack_base
|
||||
-------------------
|
||||
method
|
||||
-------------------
|
||||
pc
|
||||
-------------------
|
||||
temporaries
|
||||
-------------------
|
||||
arguments
|
||||
-------------------
|
||||
receiver
|
||||
------------------- <----- current stack_base
|
||||
....
|
||||
....
|
||||
....
|
||||
|
||||
*/
|
||||
|
||||
struct process_t
|
||||
{
|
||||
qse_word_t* stack;
|
||||
qse_word_t stack_size;
|
||||
qse_word_t stack_base;
|
||||
qse_word_t stack_top;
|
||||
|
||||
qse_word_t receiver;
|
||||
qse_word_t method;
|
||||
qse_word_t pc;
|
||||
|
||||
/* cached information about the method above */
|
||||
qse_word_t* literals;
|
||||
qse_byte_t* bytecodes;
|
||||
qse_word_t bytecode_size;
|
||||
qse_size_t argcount;
|
||||
qse_size_t tmpcount;
|
||||
};
|
||||
|
||||
typedef struct process_t process_t;
|
||||
|
||||
static int __run_process (qse_stx_t* stx, process_t* proc);
|
||||
static int __push_to_stack (qse_stx_t* stx,
|
||||
process_t* proc, qse_word_t what, qse_word_t index);
|
||||
static int __store_from_stack (qse_stx_t* stx,
|
||||
process_t* proc, qse_word_t what, qse_word_t index);
|
||||
static int __send_message (qse_stx_t* stx, process_t* proc,
|
||||
qse_word_t nargs, qse_word_t selector, qse_bool_t to_super);
|
||||
static int __return_from_message (qse_stx_t* stx, process_t* proc);
|
||||
static int __dispatch_primitive (qse_stx_t* stx, process_t* proc, qse_word_t no);
|
||||
|
||||
int qse_stx_interp (qse_stx_t* stx, qse_word_t receiver, qse_word_t method)
|
||||
{
|
||||
process_t proc;
|
||||
qse_stx_method_t* mthobj;
|
||||
qse_word_t i;
|
||||
int n;
|
||||
|
||||
// TODO: size of process stack.
|
||||
proc.stack = (qse_word_t*)qse_malloc (10000 * qse_sizeof(qse_word_t));
|
||||
if (proc.stack == QSE_NULL) {
|
||||
qse_printf (QSE_T("out of memory in qse_stx_interp\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
proc.stack_size = 10000;
|
||||
proc.stack_base = 0;
|
||||
proc.stack_top = 0;
|
||||
|
||||
mthobj = (qse_stx_method_t*)QSE_STX_OBJECT(stx,method);
|
||||
qse_assert (mthobj != QSE_NULL);
|
||||
|
||||
proc.literals = mthobj->literals;
|
||||
proc.bytecodes = QSE_STX_DATA(stx, mthobj->bytecodes);
|
||||
proc.bytecode_size = QSE_STX_SIZE(stx, mthobj->bytecodes);
|
||||
/* TODO: disable the method with arguments for start-up */
|
||||
proc.argcount = QSE_STX_FROM_SMALLINT(mthobj->argcount);
|
||||
proc.tmpcount = QSE_STX_FROM_SMALLINT(mthobj->tmpcount);
|
||||
|
||||
proc.receiver = receiver;
|
||||
proc.method = method;
|
||||
proc.pc = 0;
|
||||
|
||||
proc.stack_base = proc.stack_top;
|
||||
|
||||
/* push the receiver */
|
||||
proc.stack[proc.stack_top++] = receiver;
|
||||
|
||||
/* push arguments */
|
||||
for (i = 0; i < proc.argcount; i++) {
|
||||
proc.stack[proc.stack_top++] = stx->nil;
|
||||
}
|
||||
|
||||
/* secure space for temporaries */
|
||||
for (i = 0; i < proc.tmpcount; i++)
|
||||
proc.stack[proc.stack_top++] = stx->nil;
|
||||
|
||||
/* push dummy pc */
|
||||
proc.stack[proc.stack_top++] = 0;
|
||||
/* push dummy method */
|
||||
proc.stack[proc.stack_top++] = stx->nil;
|
||||
/* push dummy previous stack base */
|
||||
proc.stack[proc.stack_top++] = 0;
|
||||
|
||||
n = __run_process (stx, &proc);
|
||||
|
||||
qse_free (proc.stack);
|
||||
return n;
|
||||
}
|
||||
|
||||
static int __run_process (qse_stx_t* stx, process_t* proc)
|
||||
{
|
||||
int code, next, next2;
|
||||
|
||||
while (proc->pc < proc->bytecode_size) {
|
||||
code = proc->bytecodes[proc->pc++];
|
||||
|
||||
#ifdef DEBUG
|
||||
qse_printf (QSE_T("code = 0x%x\n"), code);
|
||||
#endif
|
||||
|
||||
if (code >= 0x00 && code <= 0x3F) {
|
||||
/* stack - push */
|
||||
__push_to_stack (stx, proc, code >> 4, code & 0x0F);
|
||||
}
|
||||
else if (code >= 0x40 && code <= 0x5F) {
|
||||
/* stack - store */
|
||||
int what = code >> 4;
|
||||
int index = code & 0x0F;
|
||||
__store_from_stack (stx, proc, code >> 4, code & 0x0F);
|
||||
}
|
||||
|
||||
/* TODO: more here .... */
|
||||
|
||||
else if (code == 0x67) {
|
||||
/* pop stack top */
|
||||
proc->stack_top--;
|
||||
}
|
||||
|
||||
/* TODO: more here .... */
|
||||
|
||||
else if (code == 0x6A) {
|
||||
proc->stack[proc->stack_top++] = stx->nil;
|
||||
}
|
||||
else if (code == 0x6B) {
|
||||
proc->stack[proc->stack_top++] = stx->true;
|
||||
}
|
||||
else if (code == 0x6C) {
|
||||
proc->stack[proc->stack_top++] = stx->false;
|
||||
}
|
||||
else if (code == 0x6D) {
|
||||
/* push receiver */
|
||||
proc->stack[proc->stack_top++] = proc->receiver;
|
||||
}
|
||||
|
||||
/* TODO: more here .... */
|
||||
|
||||
else if (code == 0x70) {
|
||||
/* send message to self */
|
||||
next = proc->bytecodes[proc->pc++];
|
||||
if (__send_message (stx, proc, next >> 5,
|
||||
proc->literals[next & 0x1F], qse_false) == -1) break;
|
||||
}
|
||||
else if (code == 0x71) {
|
||||
/* send message to super */
|
||||
next = proc->bytecodes[proc->pc++];
|
||||
if (__send_message (stx, proc, next >> 5,
|
||||
proc->literals[next & 0x1F], qse_true) == -1) break;
|
||||
}
|
||||
else if (code == 0x72) {
|
||||
/* send message to self extended */
|
||||
next = proc->bytecodes[proc->pc++];
|
||||
next2 = proc->bytecodes[proc->pc++];
|
||||
if (__send_message (stx, proc, next >> 5,
|
||||
proc->literals[next2], qse_false) == -1) break;
|
||||
}
|
||||
else if (code == 0x73) {
|
||||
/* send message to super extended */
|
||||
next = proc->bytecodes[proc->pc++];
|
||||
next2 = proc->bytecodes[proc->pc++];
|
||||
if (__send_message (stx, proc, next >> 5,
|
||||
proc->literals[next2], qse_true) == -1) break;
|
||||
}
|
||||
|
||||
/* more code .... */
|
||||
else if (code == 0x78) {
|
||||
/* return receiver */
|
||||
proc->stack[proc->stack_top++] = proc->receiver;
|
||||
if (__return_from_message (stx, proc) == -1) break;
|
||||
}
|
||||
|
||||
else if (code == 0x7C) {
|
||||
/* return from message */
|
||||
if (__return_from_message (stx, proc) == -1) break;
|
||||
}
|
||||
|
||||
else if (code >= 0xF0 && code <= 0xFF) {
|
||||
/* primitive */
|
||||
next = proc->bytecodes[proc->pc++];
|
||||
__dispatch_primitive (stx, proc, ((code & 0x0F) << 8) | next);
|
||||
}
|
||||
|
||||
else {
|
||||
qse_printf (QSE_T("INVALID OPCODE...........\n"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __push_to_stack (qse_stx_t* stx,
|
||||
process_t* proc, qse_word_t what, qse_word_t index)
|
||||
{
|
||||
switch (what) {
|
||||
case 0: /* receiver variable */
|
||||
proc->stack[proc->stack_top++] =
|
||||
QSE_STX_WORD_AT(stx, proc->stack[proc->stack_base], index);
|
||||
break;
|
||||
case 1: /* temporary variable */
|
||||
proc->stack[proc->stack_top++] =
|
||||
proc->stack[proc->stack_base + 1 + index];
|
||||
break;
|
||||
case 2: /* literal constant */
|
||||
proc->stack[proc->stack_top++] = proc->literals[index];
|
||||
break;
|
||||
case 3: /* literal variable */
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __store_from_stack (qse_stx_t* stx,
|
||||
process_t* proc, qse_word_t what, qse_word_t index)
|
||||
{
|
||||
switch (what) {
|
||||
case 4: /* receiver variable */
|
||||
QSE_STX_WORD_AT(stx,proc->stack[proc->stack_base],index) = proc->stack[--proc->stack_top];
|
||||
break;
|
||||
case 5: /* temporary location */
|
||||
proc->stack[proc->stack_base + 1 + index] = proc->stack[--proc->stack_top];
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __send_message (qse_stx_t* stx, process_t* proc,
|
||||
qse_word_t nargs, qse_word_t selector, qse_bool_t to_super)
|
||||
{
|
||||
qse_word_t receiver, method;
|
||||
qse_word_t i, tmpcount, argcount;
|
||||
qse_stx_method_t* mthobj;
|
||||
|
||||
qse_assert (QSE_STX_CLASS(stx,selector) == stx->class_symbol);
|
||||
|
||||
receiver = proc->stack[proc->stack_top - nargs - 1];
|
||||
method = qse_stx_lookup_method (
|
||||
stx, QSE_STX_CLASS(stx,receiver),
|
||||
QSE_STX_DATA(stx,selector), to_super);
|
||||
if (method == stx->nil) {
|
||||
qse_printf (QSE_T("cannot find the method....\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
mthobj = (qse_stx_method_t*)QSE_STX_OBJECT(stx,method);
|
||||
|
||||
argcount = QSE_STX_FROM_SMALLINT(mthobj->argcount);
|
||||
tmpcount = QSE_STX_FROM_SMALLINT(mthobj->tmpcount);
|
||||
qse_assert (argcount == nargs);
|
||||
|
||||
/* secure space for temporaries */
|
||||
for (i = 0; i < tmpcount; i++) {
|
||||
proc->stack[proc->stack_top++] = stx->nil;
|
||||
}
|
||||
|
||||
/* push pc */
|
||||
proc->stack[proc->stack_top++] = proc->pc;
|
||||
/* push method */
|
||||
proc->stack[proc->stack_top++] = proc->method;
|
||||
/* push previous stack base */
|
||||
proc->stack[proc->stack_top++] = proc->stack_base;
|
||||
|
||||
proc->stack_base = proc->stack_top - 3 - tmpcount - argcount - 1;
|
||||
qse_assert (proc->stack_base > 0);
|
||||
|
||||
proc->receiver = receiver;
|
||||
proc->method = method;
|
||||
proc->pc = 0;
|
||||
|
||||
proc->literals = mthobj->literals;
|
||||
proc->bytecodes = QSE_STX_DATA(stx, mthobj->bytecodes);
|
||||
proc->bytecode_size = QSE_STX_SIZE(stx, mthobj->bytecodes);
|
||||
proc->argcount = argcount;
|
||||
proc->tmpcount = tmpcount;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __return_from_message (qse_stx_t* stx, process_t* proc)
|
||||
{
|
||||
qse_word_t method, pc, stack_base;
|
||||
qse_stx_method_t* mthobj;
|
||||
|
||||
if (proc->stack_base == 0) {
|
||||
/* return from the startup method */
|
||||
return -1;
|
||||
}
|
||||
|
||||
stack_base = proc->stack[proc->stack_base + 1 + proc->tmpcount + proc->argcount + 2];
|
||||
method = proc->stack[proc->stack_base + 1 + proc->tmpcount + proc->argcount + 1];
|
||||
pc = proc->stack[proc->stack_base + 1 + proc->tmpcount + proc->argcount];
|
||||
|
||||
mthobj = (qse_stx_method_t*)QSE_STX_OBJECT(stx,method);
|
||||
qse_assert (mthobj != QSE_NULL);
|
||||
|
||||
/* return value is located on top of the previous stack */
|
||||
proc->stack[proc->stack_base - 1] = proc->stack[proc->stack_top - 1];
|
||||
|
||||
/* restore the stack pointers */
|
||||
proc->stack_top = proc->stack_base;
|
||||
proc->stack_base = stack_base;
|
||||
|
||||
proc->receiver = proc->stack[stack_base];
|
||||
proc->method = method;
|
||||
proc->pc = pc;
|
||||
|
||||
proc->literals = mthobj->literals;
|
||||
proc->bytecodes = QSE_STX_DATA(stx, mthobj->bytecodes);
|
||||
proc->bytecode_size = QSE_STX_SIZE(stx, mthobj->bytecodes);
|
||||
proc->argcount = QSE_STX_FROM_SMALLINT(mthobj->argcount);
|
||||
proc->tmpcount = QSE_STX_FROM_SMALLINT(mthobj->tmpcount);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int __dispatch_primitive (qse_stx_t* stx, process_t* proc, qse_word_t no)
|
||||
{
|
||||
switch (no) {
|
||||
case 0:
|
||||
qse_printf (QSE_T("[[ hello stx smalltalk ]]\n"));
|
||||
break;
|
||||
case 1:
|
||||
qse_printf (QSE_T("<< AMAZING STX SMALLTALK WORLD >>\n"));
|
||||
break;
|
||||
case 2:
|
||||
qse_printf (QSE_T("<< FUNKY STX SMALLTALK >> %d\n"),
|
||||
QSE_STX_FROM_SMALLINT(proc->stack[proc->stack_base + 1]));
|
||||
break;
|
||||
case 3:
|
||||
qse_printf (QSE_T("<< HIGH STX SMALLTALK >> %d, %d\n"),
|
||||
QSE_STX_FROM_SMALLINT(proc->stack[proc->stack_base + 1]),
|
||||
QSE_STX_FROM_SMALLINT(proc->stack[proc->stack_base + 2]));
|
||||
break;
|
||||
case 20:
|
||||
qse_printf (QSE_T("<< PRIMITIVE 20 >>\n"));
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
20
qse/lib/stx/interp.h
Normal file
20
qse/lib/stx/interp.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* $Id: interp.h 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#ifndef _QSE_STX_INTERP_H_
|
||||
#define _QSE_STX_INTERP_H_
|
||||
|
||||
#include <qse/stx/stx.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int qse_stx_interp (qse_stx_t* stx, qse_word_t receiver, qse_word_t method);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
31
qse/lib/stx/kernel/Object.st
Normal file
31
qse/lib/stx/kernel/Object.st
Normal file
@ -0,0 +1,31 @@
|
||||
!Object methods!
|
||||
|
||||
= aValue
|
||||
^ self == aValue
|
||||
!
|
||||
|
||||
== aValue
|
||||
^ <21 self aValue>
|
||||
!
|
||||
|
||||
basicAt: index
|
||||
^<25 self index>
|
||||
!
|
||||
|
||||
basicAt: index put: value
|
||||
^<31 self index value>
|
||||
!
|
||||
|
||||
|
||||
basicSize
|
||||
^<12 self>
|
||||
!
|
||||
|
||||
|
||||
isNil
|
||||
^false.
|
||||
!
|
||||
|
||||
notNil
|
||||
^false.
|
||||
!!
|
117
qse/lib/stx/makefile.in
Normal file
117
qse/lib/stx/makefile.in
Normal file
@ -0,0 +1,117 @@
|
||||
#
|
||||
# $Id: makefile.in,v 1.4 2007/09/11 13:42:54 bacon Exp $
|
||||
#
|
||||
|
||||
NAME = asestx
|
||||
|
||||
TOP_BUILDDIR = @abs_top_builddir@
|
||||
TOP_INSTALLDIR = @prefix@/ase
|
||||
|
||||
CC = @CC@
|
||||
CXX = @CXX@
|
||||
AR = @AR@
|
||||
RANLIB = @RANLIB@
|
||||
CFLAGS = @CFLAGS@ -I@abs_top_builddir@/..
|
||||
CXXFLAGS = @CXXFLAGS@ -I@abs_top_builddir@/..
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBS = @LIBS@
|
||||
MODE = @BUILDMODE@
|
||||
|
||||
JAVAC = @JAVAC@
|
||||
JAR = @JAR@
|
||||
CFLAGS_JNI = @CFLAGS_JNI@
|
||||
JNI = @JNI@
|
||||
|
||||
LIBTOOL_COMPILE = ../libtool --mode=compile
|
||||
LIBTOOL_LINK = ../libtool --mode=link
|
||||
|
||||
OUT_DIR = ../$(MODE)/lib
|
||||
OUT_FILE_LIB = $(OUT_DIR)/lib$(NAME).a
|
||||
OUT_FILE_JNI = $(OUT_DIR)/lib$(NAME)_jni.la
|
||||
OUT_FILE_LIB_CXX = $(OUT_DIR)/lib$(NAME)++.a
|
||||
OUT_FILE_JAR = $(OUT_DIR)/$(NAME).jar
|
||||
|
||||
TMP_DIR = $(MODE)
|
||||
TMP_DIR_CXX = $(TMP_DIR)/cxx
|
||||
|
||||
OBJ_FILES_LIB = \
|
||||
$(TMP_DIR)/stx.o \
|
||||
$(TMP_DIR)/memory.o \
|
||||
$(TMP_DIR)/object.o \
|
||||
$(TMP_DIR)/symbol.o \
|
||||
$(TMP_DIR)/class.o \
|
||||
$(TMP_DIR)/array.o \
|
||||
$(TMP_DIR)/dict.o \
|
||||
$(TMP_DIR)/misc.o \
|
||||
$(TMP_DIR)/context.o \
|
||||
$(TMP_DIR)/name.o \
|
||||
$(TMP_DIR)/token.o \
|
||||
$(TMP_DIR)/parser.o \
|
||||
$(TMP_DIR)/bootstrp.o \
|
||||
$(TMP_DIR)/bytecode.o \
|
||||
$(TMP_DIR)/interp.o
|
||||
|
||||
OBJ_FILES_SO = $(OBJ_FILES_LIB:.o=.lo)
|
||||
|
||||
lib: build
|
||||
|
||||
build: $(OUT_FILE_LIB)
|
||||
|
||||
$(OUT_FILE_LIB): $(TMP_DIR) $(OUT_DIR) $(OBJ_FILES_LIB)
|
||||
$(AR) cr $(OUT_FILE_LIB) $(OBJ_FILES_LIB)
|
||||
if [ ! -z "$(RANLIB)" ]; then $(RANLIB) $(OUT_FILE_LIB); fi
|
||||
|
||||
$(TMP_DIR)/stx.o: stx.c
|
||||
$(LIBTOOL_COMPILE) $(CC) $(CFLAGS) -o $@ -c stx.c
|
||||
|
||||
$(TMP_DIR)/memory.o: memory.c
|
||||
$(LIBTOOL_COMPILE) $(CC) $(CFLAGS) -o $@ -c memory.c
|
||||
|
||||
$(TMP_DIR)/object.o: object.c
|
||||
$(LIBTOOL_COMPILE) $(CC) $(CFLAGS) -o $@ -c object.c
|
||||
|
||||
$(TMP_DIR)/symbol.o: symbol.c
|
||||
$(LIBTOOL_COMPILE) $(CC) $(CFLAGS) -o $@ -c symbol.c
|
||||
|
||||
$(TMP_DIR)/class.o: class.c
|
||||
$(LIBTOOL_COMPILE) $(CC) $(CFLAGS) -o $@ -c class.c
|
||||
|
||||
$(TMP_DIR)/array.o: array.c
|
||||
$(LIBTOOL_COMPILE) $(CC) $(CFLAGS) -o $@ -c array.c
|
||||
|
||||
$(TMP_DIR)/dict.o: dict.c
|
||||
$(LIBTOOL_COMPILE) $(CC) $(CFLAGS) -o $@ -c dict.c
|
||||
|
||||
$(TMP_DIR)/misc.o: misc.c
|
||||
$(LIBTOOL_COMPILE) $(CC) $(CFLAGS) -o $@ -c misc.c
|
||||
|
||||
$(TMP_DIR)/context.o: context.c
|
||||
$(LIBTOOL_COMPILE) $(CC) $(CFLAGS) -o $@ -c context.c
|
||||
|
||||
$(TMP_DIR)/name.o: name.c
|
||||
$(LIBTOOL_COMPILE) $(CC) $(CFLAGS) -o $@ -c name.c
|
||||
|
||||
$(TMP_DIR)/token.o: token.c
|
||||
$(LIBTOOL_COMPILE) $(CC) $(CFLAGS) -o $@ -c token.c
|
||||
|
||||
$(TMP_DIR)/parser.o: parser.c
|
||||
$(LIBTOOL_COMPILE) $(CC) $(CFLAGS) -o $@ -c parser.c
|
||||
|
||||
$(TMP_DIR)/bootstrp.o: bootstrp.c
|
||||
$(LIBTOOL_COMPILE) $(CC) $(CFLAGS) -o $@ -c bootstrp.c
|
||||
|
||||
$(TMP_DIR)/bytecode.o: bytecode.c
|
||||
$(LIBTOOL_COMPILE) $(CC) $(CFLAGS) -o $@ -c bytecode.c
|
||||
|
||||
$(TMP_DIR)/interp.o: interp.c
|
||||
$(LIBTOOL_COMPILE) $(CC) $(CFLAGS) -o $@ -c interp.c
|
||||
|
||||
$(OUT_DIR):
|
||||
mkdir -p $(OUT_DIR)
|
||||
|
||||
$(TMP_DIR):
|
||||
mkdir -p $(TMP_DIR)
|
||||
|
||||
clean:
|
||||
rm -rf $(OUT_FILE_LIB) $(OBJ_FILES_LIB)
|
||||
|
98
qse/lib/stx/memory.c
Normal file
98
qse/lib/stx/memory.c
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* $Id: memory.c 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#include <qse/stx/memory.h>
|
||||
#include <qse/stx/misc.h>
|
||||
|
||||
qse_stx_memory_t* qse_stx_memory_open (
|
||||
qse_stx_memory_t* mem, qse_word_t capacity)
|
||||
{
|
||||
qse_stx_object_t** slots;
|
||||
qse_word_t n;
|
||||
|
||||
qse_assert (capacity > 0);
|
||||
if (mem == QSE_NULL) {
|
||||
mem = (qse_stx_memory_t*)qse_malloc(qse_sizeof(qse_stx_memory_t));
|
||||
if (mem == QSE_NULL) return QSE_NULL;
|
||||
mem->__dynamic = qse_true;
|
||||
}
|
||||
else mem->__dynamic = qse_false;
|
||||
|
||||
slots = (qse_stx_object_t**)qse_malloc (
|
||||
capacity * qse_sizeof(qse_stx_object_t*));
|
||||
if (slots == QSE_NULL) {
|
||||
if (mem->__dynamic) qse_free (mem);
|
||||
mem = QSE_NULL;
|
||||
}
|
||||
|
||||
mem->capacity = capacity;
|
||||
mem->slots = slots;
|
||||
|
||||
/* weave the free slot list */
|
||||
mem->free = &slots[0];
|
||||
for (n = 0; n < capacity - 1; n++) {
|
||||
mem->slots[n] = (qse_stx_object_t*)&mem->slots[n + 1];
|
||||
}
|
||||
mem->slots[n] = QSE_NULL;
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
void qse_stx_memory_close (qse_stx_memory_t* mem)
|
||||
{
|
||||
/* TODO: free all linked objects... */
|
||||
|
||||
qse_free (mem->slots);
|
||||
mem->capacity = 0;
|
||||
mem->slots = QSE_NULL;
|
||||
mem->free = QSE_NULL;
|
||||
if (mem->__dynamic) qse_free (mem);
|
||||
}
|
||||
|
||||
void qse_stx_memory_gc (qse_stx_memory_t* mem)
|
||||
{
|
||||
/* TODO: implement this function */
|
||||
}
|
||||
|
||||
qse_word_t qse_stx_memory_alloc (qse_stx_memory_t* mem, qse_word_t nbytes)
|
||||
{
|
||||
qse_stx_object_t** slot;
|
||||
qse_stx_object_t* object;
|
||||
|
||||
/* find the free object slot */
|
||||
if (mem->free == QSE_NULL) {
|
||||
qse_stx_memory_gc (mem);
|
||||
if (mem->free == QSE_NULL) return mem->capacity;;
|
||||
}
|
||||
|
||||
object = (qse_stx_object_t*)qse_malloc (nbytes);
|
||||
if (object == QSE_NULL) {
|
||||
qse_stx_memory_gc (mem);
|
||||
object = (qse_stx_object_t*)qse_malloc (nbytes);
|
||||
/*if (object == QSE_NULL) return mem->capacity;*/
|
||||
if (object == QSE_NULL) {
|
||||
qse_assert (QSE_T("MEMORY ALLOCATION ERROR\n") == QSE_NULL);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
slot = mem->free;
|
||||
mem->free = (qse_stx_object_t**)*slot;
|
||||
*slot = object;
|
||||
|
||||
return (qse_word_t)(slot - mem->slots);
|
||||
}
|
||||
|
||||
void qse_stx_memory_dealloc (qse_stx_memory_t* mem, qse_word_t object_index)
|
||||
{
|
||||
/*
|
||||
* THIS IS PRIMITIVE LOW-LEVEL DEALLOC. THIS WILL NOT
|
||||
* DEALLOCATE MEMORY ALLOCATED FOR ITS INSTANCE VARIABLES.
|
||||
*/
|
||||
|
||||
qse_free (mem->slots[object_index]);
|
||||
mem->slots[object_index] = (qse_stx_object_t*)mem->free;
|
||||
mem->free = &mem->slots[object_index];
|
||||
}
|
||||
|
26
qse/lib/stx/memory.h
Normal file
26
qse/lib/stx/memory.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* $Id: memory.h 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#ifndef _QSE_STX_MEMORY_H_
|
||||
#define _QSE_STX_MEMORY_H_
|
||||
|
||||
#include <qse/stx/stx.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
qse_stx_memory_t* qse_stx_memory_open (
|
||||
qse_stx_memory_t* mem, qse_word_t capacity);
|
||||
void qse_stx_memory_close (qse_stx_memory_t* mem);
|
||||
|
||||
void qse_stx_memory_gc (qse_stx_memory_t* mem);
|
||||
qse_word_t qse_stx_memory_alloc (qse_stx_memory_t* mem, qse_word_t size);
|
||||
void qse_stx_memory_dealloc (qse_stx_memory_t* mem, qse_word_t object_index);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
50
qse/lib/stx/method.h
Normal file
50
qse/lib/stx/method.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* $Id: method.h 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#ifndef _QSE_STX_METHOD_H_
|
||||
#define _QSE_STX_METHOD_H_
|
||||
|
||||
#include <qse/stx/stx.h>
|
||||
|
||||
#define QSE_STX_METHOD_SIZE 5
|
||||
#define QSE_STX_METHOD_TEXT 0
|
||||
#define QSE_STX_METHOD_SELECTOR 1
|
||||
#define QSE_STX_METHOD_BYTECODES 2
|
||||
#define QSE_STX_METHOD_TMPCOUNT 3
|
||||
#define QSE_STX_METHOD_ARGCOUNT 4
|
||||
|
||||
|
||||
/* dolphin smalltalk's flags representation
|
||||
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
||||
-------------------------------------------------------------------------------------------------
|
||||
| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 1| | | | 0| 0| 0| 1|
|
||||
-------------------------------------------------------------------------------------------------
|
||||
\----------|-----------/ \----------|----------/ \---------|-----------/ | \---|--/ |
|
||||
extraIndex arg Count temp Count | flags |
|
||||
| |
|
||||
Block flag SmallInteger flag"
|
||||
*/
|
||||
|
||||
struct qse_stx_method_t
|
||||
{
|
||||
qse_stx_objhdr_t header;
|
||||
qse_word_t text;
|
||||
qse_word_t selector; /* is this necessary? */
|
||||
qse_word_t bytecodes;
|
||||
qse_word_t tmpcount;
|
||||
qse_word_t argcount;
|
||||
qse_word_t literals[1];
|
||||
};
|
||||
|
||||
typedef struct qse_stx_method_t qse_stx_method_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
70
qse/lib/stx/misc.c
Normal file
70
qse/lib/stx/misc.c
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* $Id: misc.c 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#include <qse/stx/misc.h>
|
||||
|
||||
qse_word_t qse_stx_hash (const void* data, qse_word_t len)
|
||||
{
|
||||
qse_word_t h = 0;
|
||||
qse_byte_t* bp, * be;
|
||||
|
||||
bp = (qse_byte_t*)data; be = bp + len;
|
||||
while (bp < be) h = h * 31 + *bp++;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
qse_word_t qse_stx_strhash (const qse_char_t* str)
|
||||
{
|
||||
qse_word_t h = 0;
|
||||
qse_byte_t* bp, * be;
|
||||
const qse_char_t* p = str;
|
||||
|
||||
while (*p != QSE_T('\0')) {
|
||||
bp = (qse_byte_t*)p;
|
||||
be = bp + qse_sizeof(qse_char_t);
|
||||
while (bp < be) h = h * 31 + *bp++;
|
||||
p++;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
qse_word_t qse_stx_strxhash (const qse_char_t* str, qse_word_t len)
|
||||
{
|
||||
qse_word_t h = 0;
|
||||
qse_byte_t* bp, * be;
|
||||
const qse_char_t* p = str, * end = str + len;
|
||||
|
||||
while (p < end) {
|
||||
bp = (qse_byte_t*)p;
|
||||
be = bp + qse_sizeof(qse_char_t);
|
||||
while (bp < be) h = h * 31 + *bp++;
|
||||
p++;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
qse_char_t* qse_stx_strword (
|
||||
const qse_char_t* str, const qse_char_t* word, qse_word_t* word_index)
|
||||
{
|
||||
qse_char_t* p = (qse_char_t*)str;
|
||||
qse_char_t* tok;
|
||||
qse_size_t len;
|
||||
qse_word_t index = 0;
|
||||
|
||||
while (p != QSE_NULL) {
|
||||
p = qse_strtok (p, QSE_T(""), &tok, &len);
|
||||
if (qse_strxcmp (tok, len, word) == 0) {
|
||||
*word_index = index;
|
||||
return tok;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
*word_index = index;
|
||||
return QSE_NULL;
|
||||
}
|
63
qse/lib/stx/misc.h
Normal file
63
qse/lib/stx/misc.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* $Id: misc.h 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#ifndef _QSE_STX_MISC_H_
|
||||
#define _QSE_STX_MISC_H_
|
||||
|
||||
#include <qse/stx/stx.h>
|
||||
|
||||
/* TODO: remove this header later */
|
||||
#include <qse/bas/stdio.h>
|
||||
|
||||
#ifdef _DOS
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define qse_assert assert
|
||||
#define qse_malloc malloc
|
||||
#define qse_realloc realloc
|
||||
#define qse_free free
|
||||
#define qse_va_list va_list
|
||||
#define qse_va_start va_start
|
||||
#define qse_va_end va_end
|
||||
#define qse_va_arg va_arg
|
||||
#define qse_isspace isspace
|
||||
#define qse_isdigit isdigit
|
||||
#define qse_isalpha isalpha
|
||||
#define qse_isalnum isalnum
|
||||
#else
|
||||
#include <qse/bas/memory.h>
|
||||
#include <qse/bas/assert.h>
|
||||
#include <qse/bas/stdarg.h>
|
||||
#include <qse/bas/ctype.h>
|
||||
#include <qse/bas/string.h>
|
||||
#include <qse/bas/stdlib.h>
|
||||
#endif
|
||||
|
||||
#if defined(__BORLANDC__) || defined(_MSC_VER)
|
||||
#define INLINE
|
||||
#else
|
||||
#define INLINE inline
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
qse_word_t qse_stx_hash (const void* data, qse_word_t len);
|
||||
qse_word_t qse_stx_strhash (const qse_char_t* str);
|
||||
qse_word_t qse_stx_strxhash (const qse_char_t* str, qse_word_t len);
|
||||
|
||||
qse_char_t* qse_stx_strword (
|
||||
const qse_char_t* str, const qse_char_t* word, qse_word_t* word_index);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
146
qse/lib/stx/name.c
Normal file
146
qse/lib/stx/name.c
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* $Id: name.c 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#include <qse/stx/name.h>
|
||||
#include <qse/stx/misc.h>
|
||||
|
||||
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;
|
||||
}
|
39
qse/lib/stx/name.h
Normal file
39
qse/lib/stx/name.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* $Id: name.h 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#ifndef _QSE_STX_NAME_H_
|
||||
#define _QSE_STX_NAME_H_
|
||||
|
||||
#include <qse/stx/stx.h>
|
||||
|
||||
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
|
246
qse/lib/stx/object.c
Normal file
246
qse/lib/stx/object.c
Normal file
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* $Id: object.c 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#include <qse/stx/object.h>
|
||||
#include <qse/stx/memory.h>
|
||||
#include <qse/stx/symbol.h>
|
||||
#include <qse/stx/class.h>
|
||||
#include <qse/stx/misc.h>
|
||||
|
||||
/* n: number of instance variables */
|
||||
qse_word_t qse_stx_alloc_word_object (
|
||||
qse_stx_t* stx, const qse_word_t* data, qse_word_t nfields,
|
||||
const qse_word_t* variable_data, qse_word_t variable_nfields)
|
||||
{
|
||||
qse_word_t idx, n;
|
||||
qse_stx_word_object_t* obj;
|
||||
|
||||
qse_assert (stx->nil == QSE_STX_NIL);
|
||||
|
||||
/* bytes to allocated =
|
||||
* (number of instance variables +
|
||||
* number of variable instance variables) * word_size
|
||||
*/
|
||||
n = nfields + variable_nfields;
|
||||
idx = qse_stx_memory_alloc (&stx->memory,
|
||||
n * qse_sizeof(qse_word_t) + qse_sizeof(qse_stx_object_t));
|
||||
if (idx >= stx->memory.capacity) return idx; /* failed TODO: return a difference value OINDEX_INVALID */
|
||||
|
||||
idx = QSE_STX_TO_OINDEX(idx);
|
||||
obj = QSE_STX_WORD_OBJECT(stx,idx);
|
||||
obj->header.class = stx->nil;
|
||||
obj->header.access = (n << 2) | QSE_STX_WORD_INDEXED;
|
||||
|
||||
if (variable_data == QSE_NULL) {
|
||||
while (n > nfields) obj->data[--n] = stx->nil;
|
||||
}
|
||||
else {
|
||||
while (n > nfields) {
|
||||
n--; obj->data[n] = variable_data[n - nfields];
|
||||
}
|
||||
}
|
||||
|
||||
if (data == QSE_NULL) {
|
||||
while (n > 0) obj->data[--n] = stx->nil;
|
||||
}
|
||||
else {
|
||||
while (n > 0) {
|
||||
n--; obj->data[n] = data[n];
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
/* n: number of bytes */
|
||||
qse_word_t qse_stx_alloc_byte_object (
|
||||
qse_stx_t* stx, const qse_byte_t* data, qse_word_t n)
|
||||
{
|
||||
qse_word_t idx;
|
||||
qse_stx_byte_object_t* obj;
|
||||
|
||||
qse_assert (stx->nil == QSE_STX_NIL);
|
||||
|
||||
idx = qse_stx_memory_alloc (
|
||||
&stx->memory, n + qse_sizeof(qse_stx_object_t));
|
||||
if (idx >= stx->memory.capacity) return idx; /* failed */
|
||||
|
||||
idx = QSE_STX_TO_OINDEX(idx);
|
||||
obj = QSE_STX_BYTE_OBJECT(stx,idx);
|
||||
obj->header.class = stx->nil;
|
||||
obj->header.access = (n << 2) | QSE_STX_BYTE_INDEXED;
|
||||
|
||||
if (data == QSE_NULL) {
|
||||
while (n-- > 0) obj->data[n] = 0;
|
||||
}
|
||||
else {
|
||||
while (n-- > 0) obj->data[n] = data[n];
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
qse_word_t qse_stx_alloc_char_object (
|
||||
qse_stx_t* stx, const qse_char_t* str)
|
||||
{
|
||||
return (str == QSE_NULL)?
|
||||
qse_stx_alloc_char_objectx (stx, QSE_NULL, 0):
|
||||
qse_stx_alloc_char_objectx (stx, str, qse_strlen(str));
|
||||
}
|
||||
|
||||
/* n: number of characters */
|
||||
qse_word_t qse_stx_alloc_char_objectx (
|
||||
qse_stx_t* stx, const qse_char_t* str, qse_word_t n)
|
||||
{
|
||||
qse_word_t idx;
|
||||
qse_stx_char_object_t* obj;
|
||||
|
||||
qse_assert (stx->nil == QSE_STX_NIL);
|
||||
|
||||
idx = qse_stx_memory_alloc (&stx->memory,
|
||||
(n + 1) * qse_sizeof(qse_char_t) + qse_sizeof(qse_stx_object_t));
|
||||
if (idx >= stx->memory.capacity) return idx; /* failed */
|
||||
|
||||
idx = QSE_STX_TO_OINDEX(idx);
|
||||
obj = QSE_STX_CHAR_OBJECT(stx,idx);
|
||||
obj->header.class = stx->nil;
|
||||
obj->header.access = (n << 2) | QSE_STX_CHAR_INDEXED;
|
||||
obj->data[n] = QSE_T('\0');
|
||||
|
||||
if (str == QSE_NULL) {
|
||||
while (n-- > 0) obj->data[n] = QSE_T('\0');
|
||||
}
|
||||
else {
|
||||
while (n-- > 0) obj->data[n] = str[n];
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
qse_word_t qse_stx_allocn_char_object (qse_stx_t* stx, ...)
|
||||
{
|
||||
qse_word_t idx, n = 0;
|
||||
const qse_char_t* p;
|
||||
qse_va_list ap;
|
||||
qse_stx_char_object_t* obj;
|
||||
|
||||
qse_assert (stx->nil == QSE_STX_NIL);
|
||||
|
||||
qse_va_start (ap, stx);
|
||||
while ((p = qse_va_arg(ap, const qse_char_t*)) != QSE_NULL) {
|
||||
n += qse_strlen(p);
|
||||
}
|
||||
qse_va_end (ap);
|
||||
|
||||
idx = qse_stx_memory_alloc (&stx->memory,
|
||||
(n + 1) * qse_sizeof(qse_char_t) + qse_sizeof(qse_stx_object_t));
|
||||
if (idx >= stx->memory.capacity) return idx; /* failed */
|
||||
|
||||
idx = QSE_STX_TO_OINDEX(idx);
|
||||
obj = QSE_STX_CHAR_OBJECT(stx,idx);
|
||||
obj->header.class = stx->nil;
|
||||
obj->header.access = (n << 2) | QSE_STX_CHAR_INDEXED;
|
||||
obj->data[n] = QSE_T('\0');
|
||||
|
||||
qse_va_start (ap, stx);
|
||||
n = 0;
|
||||
while ((p = qse_va_arg(ap, const qse_char_t*)) != QSE_NULL) {
|
||||
while (*p != QSE_T('\0')) {
|
||||
/*QSE_STX_CHAR_AT(stx,idx,n++) = *p++;*/
|
||||
obj->data[n++] = *p++;
|
||||
}
|
||||
}
|
||||
qse_va_end (ap);
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
qse_word_t qse_stx_hash_object (qse_stx_t* stx, qse_word_t object)
|
||||
{
|
||||
qse_word_t hv;
|
||||
|
||||
if (QSE_STX_IS_SMALLINT(object)) {
|
||||
qse_word_t tmp = QSE_STX_FROM_SMALLINT(object);
|
||||
hv = qse_stx_hash(&tmp, qse_sizeof(tmp));
|
||||
}
|
||||
else if (QSE_STX_IS_CHAR_OBJECT(stx,object)) {
|
||||
/* the additional null is not taken into account */
|
||||
hv = qse_stx_hash (QSE_STX_DATA(stx,object),
|
||||
QSE_STX_SIZE(stx,object) * qse_sizeof(qse_char_t));
|
||||
}
|
||||
else if (QSE_STX_IS_BYTE_OBJECT(stx,object)) {
|
||||
hv = qse_stx_hash (
|
||||
QSE_STX_DATA(stx,object), QSE_STX_SIZE(stx,object));
|
||||
}
|
||||
else {
|
||||
qse_assert (QSE_STX_IS_WORD_OBJECT(stx,object));
|
||||
hv = qse_stx_hash (QSE_STX_DATA(stx,object),
|
||||
QSE_STX_SIZE(stx,object) * qse_sizeof(qse_word_t));
|
||||
}
|
||||
|
||||
return hv;
|
||||
}
|
||||
|
||||
qse_word_t qse_stx_instantiate (
|
||||
qse_stx_t* stx, qse_word_t class, const void* data,
|
||||
const void* variable_data, qse_word_t variable_nfields)
|
||||
{
|
||||
qse_stx_class_t* class_obj;
|
||||
qse_word_t spec, nfields, new;
|
||||
int indexable;
|
||||
|
||||
qse_assert (class != stx->class_smallinteger);
|
||||
class_obj = (qse_stx_class_t*)QSE_STX_OBJECT(stx, class);
|
||||
|
||||
/* don't instantiate a metaclass whose instance must be
|
||||
created in a different way */
|
||||
/* TODO: maybe delete the following line */
|
||||
qse_assert (class_obj->header.class != stx->class_metaclass);
|
||||
qse_assert (QSE_STX_IS_SMALLINT(class_obj->spec));
|
||||
|
||||
spec = QSE_STX_FROM_SMALLINT(class_obj->spec);
|
||||
nfields = (spec >> QSE_STX_SPEC_INDEXABLE_BITS);
|
||||
indexable = spec & QSE_STX_SPEC_INDEXABLE_MASK;
|
||||
|
||||
if (indexable == QSE_STX_SPEC_BYTE_INDEXABLE) {
|
||||
qse_assert (nfields == 0 && data == QSE_NULL);
|
||||
new = qse_stx_alloc_byte_object(
|
||||
stx, variable_data, variable_nfields);
|
||||
}
|
||||
else if (indexable == QSE_STX_SPEC_CHAR_INDEXABLE) {
|
||||
qse_assert (nfields == 0 && data == QSE_NULL);
|
||||
new = qse_stx_alloc_char_objectx(
|
||||
stx, variable_data, variable_nfields);
|
||||
}
|
||||
else if (indexable == QSE_STX_SPEC_WORD_INDEXABLE) {
|
||||
new = qse_stx_alloc_word_object (
|
||||
stx, data, nfields, variable_data, variable_nfields);
|
||||
}
|
||||
else {
|
||||
qse_assert (indexable == QSE_STX_SPEC_NOT_INDEXABLE);
|
||||
qse_assert (variable_nfields == 0 && variable_data == QSE_NULL);
|
||||
new = qse_stx_alloc_word_object (
|
||||
stx, data, nfields, QSE_NULL, 0);
|
||||
}
|
||||
|
||||
QSE_STX_CLASS(stx, new) = class;
|
||||
return new;
|
||||
}
|
||||
|
||||
qse_word_t qse_stx_class (qse_stx_t* stx, qse_word_t obj)
|
||||
{
|
||||
return QSE_STX_IS_SMALLINT(obj)?
|
||||
stx->class_smallinteger: QSE_STX_CLASS(stx,obj);
|
||||
}
|
||||
|
||||
qse_word_t qse_stx_classof (qse_stx_t* stx, qse_word_t obj)
|
||||
{
|
||||
return QSE_STX_IS_SMALLINT(obj)?
|
||||
stx->class_smallinteger: QSE_STX_CLASS(stx,obj);
|
||||
}
|
||||
|
||||
qse_word_t qse_stx_sizeof (qse_stx_t* stx, qse_word_t obj)
|
||||
{
|
||||
return QSE_STX_IS_SMALLINT(obj)? 1: QSE_STX_SIZE(stx,obj);
|
||||
}
|
40
qse/lib/stx/object.h
Normal file
40
qse/lib/stx/object.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* $Id: object.h 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#ifndef _QSE_STX_OBJECT_H_
|
||||
#define _QSE_STX_OBJECT_H_
|
||||
|
||||
#include <qse/stx/stx.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
qse_word_t qse_stx_alloc_word_object (
|
||||
qse_stx_t* stx, const qse_word_t* data, qse_word_t nfields,
|
||||
const qse_word_t* variable_data, qse_word_t variable_nfields);
|
||||
|
||||
qse_word_t qse_stx_alloc_byte_object (
|
||||
qse_stx_t* stx, const qse_byte_t* data, qse_word_t n);
|
||||
|
||||
qse_word_t qse_stx_alloc_char_object (
|
||||
qse_stx_t* stx, const qse_char_t* str);
|
||||
qse_word_t qse_stx_alloc_char_objectx (
|
||||
qse_stx_t* stx, const qse_char_t* str, qse_word_t n);
|
||||
qse_word_t qse_stx_allocn_char_object (qse_stx_t* stx, ...);
|
||||
|
||||
qse_word_t qse_stx_hash_object (qse_stx_t* stx, qse_word_t object);
|
||||
|
||||
qse_word_t qse_stx_instantiate (
|
||||
qse_stx_t* stx, qse_word_t class_index, const void* data,
|
||||
const void* variable_data, qse_word_t variable_nfields);
|
||||
qse_word_t qse_stx_classof (qse_stx_t* stx, qse_word_t obj);
|
||||
qse_word_t qse_stx_sizeof (qse_stx_t* stx, qse_word_t obj);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
1608
qse/lib/stx/parser.c
Normal file
1608
qse/lib/stx/parser.c
Normal file
File diff suppressed because it is too large
Load Diff
107
qse/lib/stx/parser.h
Normal file
107
qse/lib/stx/parser.h
Normal file
@ -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 <qse/stx/stx.h>
|
||||
#include <qse/stx/name.h>
|
||||
#include <qse/stx/token.h>
|
||||
#include <qse/bas/arr.h>
|
||||
|
||||
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
|
196
qse/lib/stx/stx.bnf
Normal file
196
qse/lib/stx/stx.bnf
Normal file
@ -0,0 +1,196 @@
|
||||
~~~ method grammar ~~~
|
||||
|
||||
<method definition> ::=
|
||||
<message pattern>
|
||||
[<temporaries> ]
|
||||
[<statements>]
|
||||
|
||||
<message pattern> ::= <unary pattern> |
|
||||
<binary pattern> |
|
||||
<keyword pattern>
|
||||
|
||||
<unary pattern> ::= unarySelector
|
||||
|
||||
<binary pattern> ::= binarySelector <method argument>
|
||||
|
||||
<keyword pattern> ::= (keyword <method argument>)+
|
||||
|
||||
<temporaries> ::= '|' <temporary variable list> '|'
|
||||
|
||||
<temporary variable list> ::= identifier*
|
||||
|
||||
<block constructor> ::= '[' <block body> ']'
|
||||
|
||||
<block body> ::= [<block argument>* '|']
|
||||
[<temporaries>] [<statements>]
|
||||
|
||||
<block argument> ::= ':' identifier
|
||||
|
||||
<statements> ::=
|
||||
(<return statement> ['.'] ) |
|
||||
(<expression> ['.' [<statements>]])
|
||||
|
||||
<return statement> ::= returnOperator <expression>
|
||||
|
||||
<expression> ::=
|
||||
<assignment> |
|
||||
<basic expression>
|
||||
|
||||
<assignment> ::= <assignment target> assignmentOperator <expression>
|
||||
|
||||
<basic expression> ::=
|
||||
<primary> [<messages> <cascaded messages>]
|
||||
|
||||
<assignment target> := identifier
|
||||
|
||||
<primary> ::=
|
||||
identifier |
|
||||
<literal> |
|
||||
<block constructor> |
|
||||
( '(' <expression> ')' )
|
||||
|
||||
|
||||
<messages> ::=
|
||||
(<unary message>+ <binary message>* [<keyword message>] ) |
|
||||
(<binary message>+ [<keyword message>] ) |
|
||||
<keyword message>
|
||||
|
||||
<unary message> ::= unarySelector
|
||||
|
||||
<binary message> ::= binarySelector <binary argument>
|
||||
|
||||
<binary argument> ::= <primary> <unary message>*
|
||||
|
||||
<keyword message> ::= (keyword <keyword argument> )+
|
||||
|
||||
<keyword argument> ::= <primary> <unary message>* <binary message>*
|
||||
|
||||
<cascaded messages> ::= (';' <messages>)*
|
||||
|
||||
<literal> ::=
|
||||
<number literal> |
|
||||
<string literal> |
|
||||
<character literal> |
|
||||
<symbol literal> |
|
||||
<selector literal> |
|
||||
<array literal>
|
||||
|
||||
<number literal> ::= ['-'] <number>
|
||||
|
||||
<number> ::= integer | float | scaledDecimal
|
||||
|
||||
<character literal> ::= quotedCharacter
|
||||
|
||||
<string literal> ::= quotedString
|
||||
|
||||
<symbol literal> ::= hashedString
|
||||
|
||||
<selector literal> ::= quotedSelector
|
||||
|
||||
<array literal> ::= '#(' <array element>* ')'
|
||||
|
||||
<array element> ::= <literal> | identifier
|
||||
|
||||
reserved identifiers -> nil true false self super
|
||||
|
||||
|
||||
~~~ lexical grammar ~~~
|
||||
|
||||
character ::=
|
||||
"Any character in the implementation-defined character set"
|
||||
|
||||
whitespace ::=
|
||||
"Any non-printing character interpreted as white space
|
||||
including spaces, tabs, and line breaks"
|
||||
|
||||
digit ::=
|
||||
'0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
|
||||
|
||||
uppercaseAlphabetic ::=
|
||||
'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' |
|
||||
'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' |
|
||||
'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z'
|
||||
|
||||
lowercaseAlphabetic ::=
|
||||
'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' |
|
||||
'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' |
|
||||
's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z'
|
||||
|
||||
nonCaseLetter ::= '_'
|
||||
|
||||
letter ::=
|
||||
uppercaseAlphabetic |
|
||||
lowercaseAlphabetic |
|
||||
nonCaseLetter |
|
||||
"implementation defined letters"
|
||||
|
||||
commentDelimiter ::= '"'
|
||||
|
||||
nonCommentDelimiter::=
|
||||
"any character that is not a commentDelimiter "
|
||||
|
||||
comment :=
|
||||
commentDelimiter nonCommentDelimiter * commentDelimiter
|
||||
|
||||
identifier ::= letter (letter | digit)*
|
||||
|
||||
keyword ::= identifier ':'
|
||||
|
||||
binaryCharacter ::=
|
||||
'!' | '%' | '&' | '*' | '+' | ',' |
|
||||
'/' | '<' | '=' | '>' | '?' | '@' |
|
||||
'\' | '~' | '|' | '-'
|
||||
|
||||
binarySelector ::= binaryCharacter+
|
||||
|
||||
returnOperator ::= '^'
|
||||
|
||||
assignmentOperator ::= ':='
|
||||
|
||||
|
||||
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
|
||||
|
||||
quotedCharacter ::= '$' character
|
||||
|
||||
quotedString ::= stringDelimiter stringBody stringDelimiter
|
||||
|
||||
stringBody ::= (nonStringDelimiter | (stringDelimiter stringDelimiter)*)
|
||||
|
||||
stringDelimiter ::= ''' "a single quote"
|
||||
|
||||
nonStringDelimiter ::= "any character except stringDelimiter"
|
||||
|
||||
hashedString ::= '#' quotedString
|
||||
|
||||
quotedSelector ::= '#' (unarySelector | binarySelector | keywordSelector)
|
||||
|
||||
keywordSelector ::= keyword+
|
||||
|
||||
separator ::= (whitespace | comment)*
|
||||
|
||||
|
70
qse/lib/stx/stx.c
Normal file
70
qse/lib/stx/stx.c
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* $Id: stx.c 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#include <qse/stx/stx.h>
|
||||
#include <qse/stx/memory.h>
|
||||
#include <qse/stx/misc.h>
|
||||
|
||||
qse_stx_t* qse_stx_open (qse_stx_t* stx, qse_word_t capacity)
|
||||
{
|
||||
qse_word_t i;
|
||||
|
||||
if (stx == QSE_NULL) {
|
||||
stx = (qse_stx_t*)qse_malloc (qse_sizeof(stx));
|
||||
if (stx == QSE_NULL) return QSE_NULL;
|
||||
stx->__dynamic = qse_true;
|
||||
}
|
||||
else stx->__dynamic = qse_false;
|
||||
|
||||
if (qse_stx_memory_open (&stx->memory, capacity) == QSE_NULL) {
|
||||
if (stx->__dynamic) qse_free (stx);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
stx->symtab.size = 0;
|
||||
stx->symtab.capacity = 128; /* TODO: symbol table size */
|
||||
stx->symtab.datum = (qse_word_t*)qse_malloc (
|
||||
qse_sizeof(qse_word_t) * stx->symtab.capacity);
|
||||
if (stx->symtab.datum == QSE_NULL) {
|
||||
qse_stx_memory_close (&stx->memory);
|
||||
if (stx->__dynamic) qse_free (stx);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
stx->nil = QSE_STX_NIL;
|
||||
stx->true = QSE_STX_TRUE;
|
||||
stx->false = QSE_STX_FALSE;
|
||||
|
||||
stx->smalltalk = QSE_STX_NIL;
|
||||
|
||||
stx->class_symbol = QSE_STX_NIL;
|
||||
stx->class_metaclass = QSE_STX_NIL;
|
||||
stx->class_association = QSE_STX_NIL;
|
||||
|
||||
stx->class_object = QSE_STX_NIL;
|
||||
stx->class_class = QSE_STX_NIL;
|
||||
stx->class_array = QSE_STX_NIL;
|
||||
stx->class_bytearray = QSE_STX_NIL;
|
||||
stx->class_string = QSE_STX_NIL;
|
||||
stx->class_character = QSE_STX_NIL;
|
||||
stx->class_context = QSE_STX_NIL;
|
||||
stx->class_system_dictionary = QSE_STX_NIL;
|
||||
stx->class_method = QSE_STX_NIL;
|
||||
stx->class_smallinteger = QSE_STX_NIL;
|
||||
|
||||
for (i = 0; i < stx->symtab.capacity; i++) {
|
||||
stx->symtab.datum[i] = stx->nil;
|
||||
}
|
||||
|
||||
stx->__wantabort = qse_false;
|
||||
return stx;
|
||||
}
|
||||
|
||||
void qse_stx_close (qse_stx_t* stx)
|
||||
{
|
||||
qse_free (stx->symtab.datum);
|
||||
qse_stx_memory_close (&stx->memory);
|
||||
if (stx->__dynamic) qse_free (stx);
|
||||
}
|
||||
|
163
qse/lib/stx/stx.h
Normal file
163
qse/lib/stx/stx.h
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* $Id: stx.h 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#ifndef _QSE_STX_STX_H_
|
||||
#define _QSE_STX_STX_H_
|
||||
|
||||
#include <qse/cmn/types.h>
|
||||
#include <qse/cmn/macros.h>
|
||||
|
||||
typedef struct qse_stx_objhdr_t qse_stx_objhdr_t;
|
||||
typedef struct qse_stx_object_t qse_stx_object_t;
|
||||
typedef struct qse_stx_word_object_t qse_stx_word_object_t;
|
||||
typedef struct qse_stx_byte_object_t qse_stx_byte_object_t;
|
||||
typedef struct qse_stx_char_object_t qse_stx_char_object_t;
|
||||
typedef struct qse_stx_memory_t qse_stx_memory_t;
|
||||
typedef struct qse_stx_symtab_t qse_stx_symtab_t;
|
||||
typedef struct qse_stx_t qse_stx_t;
|
||||
|
||||
/* common object structure */
|
||||
struct qse_stx_objhdr_t
|
||||
{
|
||||
/* access - type: 2; size: rest;
|
||||
* type - word indexed: 00 byte indexed: 01 char indexed: 10
|
||||
*/
|
||||
qse_word_t access;
|
||||
qse_word_t class;
|
||||
};
|
||||
|
||||
struct qse_stx_object_t
|
||||
{
|
||||
qse_stx_objhdr_t header;
|
||||
};
|
||||
|
||||
struct qse_stx_word_object_t
|
||||
{
|
||||
qse_stx_objhdr_t header;
|
||||
qse_word_t data[1];
|
||||
};
|
||||
|
||||
struct qse_stx_byte_object_t
|
||||
{
|
||||
qse_stx_objhdr_t header;
|
||||
qse_byte_t data[1];
|
||||
};
|
||||
|
||||
struct qse_stx_char_object_t
|
||||
{
|
||||
qse_stx_objhdr_t header;
|
||||
qse_char_t data[1];
|
||||
};
|
||||
|
||||
|
||||
struct qse_stx_memory_t
|
||||
{
|
||||
qse_word_t capacity;
|
||||
qse_stx_object_t** slots;
|
||||
qse_stx_object_t** free;
|
||||
qse_bool_t __dynamic;
|
||||
};
|
||||
|
||||
struct qse_stx_symtab_t
|
||||
{
|
||||
qse_word_t* datum;
|
||||
qse_word_t size;
|
||||
qse_word_t capacity;
|
||||
};
|
||||
|
||||
struct qse_stx_t
|
||||
{
|
||||
qse_stx_memory_t memory;
|
||||
qse_stx_symtab_t symtab;
|
||||
|
||||
qse_word_t nil;
|
||||
qse_word_t true;
|
||||
qse_word_t false;
|
||||
|
||||
qse_word_t smalltalk;
|
||||
|
||||
qse_word_t class_symbol;
|
||||
qse_word_t class_metaclass;
|
||||
qse_word_t class_association;
|
||||
|
||||
qse_word_t class_object;
|
||||
qse_word_t class_class;
|
||||
qse_word_t class_array;
|
||||
qse_word_t class_bytearray;
|
||||
qse_word_t class_string;
|
||||
qse_word_t class_character;
|
||||
qse_word_t class_context;
|
||||
qse_word_t class_system_dictionary;
|
||||
qse_word_t class_method;
|
||||
qse_word_t class_smallinteger;
|
||||
|
||||
qse_bool_t __dynamic;
|
||||
qse_bool_t __wantabort; /* TODO: make it a function pointer */
|
||||
};
|
||||
|
||||
#define QSE_STX_IS_SMALLINT(x) (((x) & 0x01) == 0x01)
|
||||
#define QSE_STX_TO_SMALLINT(x) (((x) << 1) | 0x01)
|
||||
#define QSE_STX_FROM_SMALLINT(x) ((x) >> 1)
|
||||
|
||||
#define QSE_STX_IS_OINDEX(x) (((x) & 0x01) == 0x00)
|
||||
#define QSE_STX_TO_OINDEX(x) (((x) << 1) | 0x00)
|
||||
#define QSE_STX_FROM_OINDEX(x) ((x) >> 1)
|
||||
|
||||
#define QSE_STX_NIL QSE_STX_TO_OINDEX(0)
|
||||
#define QSE_STX_TRUE QSE_STX_TO_OINDEX(1)
|
||||
#define QSE_STX_FALSE QSE_STX_TO_OINDEX(2)
|
||||
|
||||
#define QSE_STX_OBJECT(stx,idx) (((stx)->memory).slots[QSE_STX_FROM_OINDEX(idx)])
|
||||
#define QSE_STX_CLASS(stx,idx) (QSE_STX_OBJECT(stx,(idx))->header.class)
|
||||
#define QSE_STX_ACCESS(stx,idx) (QSE_STX_OBJECT(stx,(idx))->header.access)
|
||||
#define QSE_STX_DATA(stx,idx) ((void*)(QSE_STX_OBJECT(stx,idx) + 1))
|
||||
|
||||
#define QSE_STX_TYPE(stx,idx) (QSE_STX_ACCESS(stx,idx) & 0x03)
|
||||
#define QSE_STX_SIZE(stx,idx) (QSE_STX_ACCESS(stx,idx) >> 0x02)
|
||||
|
||||
#define QSE_STX_WORD_INDEXED (0x00)
|
||||
#define QSE_STX_BYTE_INDEXED (0x01)
|
||||
#define QSE_STX_CHAR_INDEXED (0x02)
|
||||
|
||||
#define QSE_STX_IS_WORD_OBJECT(stx,idx) \
|
||||
(QSE_STX_TYPE(stx,idx) == QSE_STX_WORD_INDEXED)
|
||||
#define QSE_STX_IS_BYTE_OBJECT(stx,idx) \
|
||||
(QSE_STX_TYPE(stx,idx) == QSE_STX_BYTE_INDEXED)
|
||||
#define QSE_STX_IS_CHAR_OBJECT(stx,idx) \
|
||||
(QSE_STX_TYPE(stx,idx) == QSE_STX_CHAR_INDEXED)
|
||||
|
||||
#define QSE_STX_WORD_OBJECT(stx,idx) \
|
||||
((qse_stx_word_object_t*)QSE_STX_OBJECT(stx,idx))
|
||||
#define QSE_STX_BYTE_OBJECT(stx,idx) \
|
||||
((qse_stx_byte_object_t*)QSE_STX_OBJECT(stx,idx))
|
||||
#define QSE_STX_CHAR_OBJECT(stx,idx) \
|
||||
((qse_stx_char_object_t*)QSE_STX_OBJECT(stx,idx))
|
||||
|
||||
/*
|
||||
#define QSE_STX_WORD_AT(stx,idx,n) \
|
||||
(((qse_word_t*)(QSE_STX_OBJECT(stx,idx) + 1))[n])
|
||||
#define QSE_STX_BYTE_AT(stx,idx,n) \
|
||||
(((qse_byte_t*)(QSE_STX_OBJECT(stx,idx) + 1))[n])
|
||||
#define QSE_STX_CHAR_AT(stx,idx,n) \
|
||||
(((qse_char_t*)(QSE_STX_OBJECT(stx,idx) + 1))[n])
|
||||
*/
|
||||
#define QSE_STX_WORD_AT(stx,idx,n) \
|
||||
(QSE_STX_WORD_OBJECT(stx,idx)->data[n])
|
||||
#define QSE_STX_BYTE_AT(stx,idx,n) \
|
||||
(QSE_STX_BYTE_OBJECT(stx,idx)->data[n])
|
||||
#define QSE_STX_CHAR_AT(stx,idx,n) \
|
||||
(QSE_STX_CHAR_OBJECT(stx,idx)->data[n])
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
qse_stx_t* qse_stx_open (qse_stx_t* stx, qse_word_t capacity);
|
||||
void qse_stx_close (qse_stx_t* stx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
90
qse/lib/stx/stx.txt
Normal file
90
qse/lib/stx/stx.txt
Normal file
@ -0,0 +1,90 @@
|
||||
stx(1) qse
|
||||
|
||||
NAME
|
||||
stx - qse smalltalk system
|
||||
|
||||
SYNOPSIS
|
||||
stx [-f imageFile] MainClass
|
||||
|
||||
DESCRIPTION
|
||||
The virtual machine executes "MainClass main" on start-up.
|
||||
|
||||
|
||||
method 1.
|
||||
push lookup_class(#MainClass) -> receiver.
|
||||
send a unary(no argument) message with the selector #main.
|
||||
return the returned value from main and exits.
|
||||
|
||||
method 2. - take a command parameter
|
||||
push lookup_class(#MainClass) -> receiver.
|
||||
push argc as an argument.
|
||||
push argv as an argument.
|
||||
send a double-argument message the the selector #main:withArgv:.
|
||||
return the returned value from #main:withArgv and exits.
|
||||
|
||||
|
||||
AUTHOR(S)
|
||||
Hyung-Hwan Chung (bacon@abiyo.net) is the sole designer and implementer of stx.
|
||||
|
||||
BUG REPORTS
|
||||
Report bugs to bacon@abiyo.net if you find any bugs. but make sure that it is really a bug before you report it.
|
||||
|
||||
COPYRIGHT
|
||||
Copyright(c) 2005 bacon@abiyo.net
|
||||
|
||||
SEE ALSO
|
||||
qse(7)
|
||||
|
||||
|
||||
-- stack bytecodes --
|
||||
0 0000 XXXX push_receiver_variable
|
||||
1 0001 XXXX push_temporary_location
|
||||
2 0010 XXXX push_literal_constant
|
||||
3 0011 XXXX push_literal_variable
|
||||
4 0100 XXXX store_receiver_variable
|
||||
5 0101 XXXX store_temporary_location
|
||||
6 0110 0000 XXXXXXXX push_receiver_variable_extended
|
||||
0110 0001 XXXXXXXX push_temporary_location_extended
|
||||
0110 0010 XXXXXXXX push_literal_constant_extended
|
||||
0110 0011 XXXXXXXX push_literal_variable_extended
|
||||
0110 0100 XXXXXXXX store_receiver_variable_extended
|
||||
0110 0101 XXXXXXXX store_temporary_location_extended
|
||||
0110 0110 unused
|
||||
0110 0111 unused
|
||||
0110 1000 pop_stack_top
|
||||
0110 1001 duplicate_stack_top
|
||||
0110 1010 push_active_context
|
||||
0110 1011 unused
|
||||
0110 1100 unused
|
||||
0110 1101 unused
|
||||
0110 1110 unused
|
||||
0110 1111 unused
|
||||
|
||||
-- send bytecodes --
|
||||
7 0111 0000 JJJKKKKK send_to_self
|
||||
0111 0001 JJJKKKKK send_to_super
|
||||
0111 0010 JJJJJJJJ KKKKKKKK send_to_self_extended
|
||||
0111 0011 JJJJJJJJ KKKKKKKK send_to_super_extended
|
||||
|
||||
0111 0100 XXXXXXXX
|
||||
0111 0101 XXXXXXXX
|
||||
0111 0110 XXXXXXXX
|
||||
0111 0111 XXXXXXXX
|
||||
|
||||
-- return bytecodes --
|
||||
0111 1000 return receiver
|
||||
0111 1001 return_true
|
||||
0111 1010 return_false
|
||||
0111 1011 return_nil
|
||||
|
||||
0111 1100 return_from_message
|
||||
0111 1101 return_from_block
|
||||
0111 1110
|
||||
0111 1111
|
||||
|
||||
-- jump bytecodes --
|
||||
8 1000 0XXX jump_forward
|
||||
1000 1XXX XXXXXXXX jump_forward
|
||||
|
||||
-- primitive --
|
||||
F 1111 XXXX XXXXXXXX do_primitive
|
102
qse/lib/stx/symbol.c
Normal file
102
qse/lib/stx/symbol.c
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* $Id: symbol.c 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#include <qse/stx/symbol.h>
|
||||
#include <qse/stx/object.h>
|
||||
#include <qse/stx/misc.h>
|
||||
|
||||
static void __grow_symtab (qse_stx_t* stx)
|
||||
{
|
||||
qse_word_t capa, ncapa, i, j;
|
||||
qse_word_t* nspace;
|
||||
|
||||
capa = stx->symtab.capacity;
|
||||
ncapa = capa << 1;
|
||||
|
||||
nspace = (qse_word_t*)qse_malloc(qse_sizeof(qse_word_t) * ncapa);
|
||||
if (nspace == QSE_NULL)
|
||||
{
|
||||
/* TODO: handle memory error */
|
||||
}
|
||||
|
||||
for (i = 0; i < capa; i++)
|
||||
{
|
||||
qse_word_t x = stx->symtab.datum[i];
|
||||
if (x == stx->nil) continue;
|
||||
|
||||
j = qse_stx_strxhash (
|
||||
QSE_STX_DATA(stx,x), QSE_STX_SIZE(stx,x)) % ncapa;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (nspace[j] == stx->nil)
|
||||
{
|
||||
nspace[j] = x;
|
||||
break;
|
||||
}
|
||||
j = (j % ncapa) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
stx->symtab.capacity = ncapa;
|
||||
qse_free (stx->symtab.datum);
|
||||
stx->symtab.datum = nspace;
|
||||
}
|
||||
|
||||
qse_word_t qse_stx_new_symbol (qse_stx_t* stx, const qse_char_t* name)
|
||||
{
|
||||
return qse_stx_new_symbolx (stx, name, qse_strlen(name));
|
||||
}
|
||||
|
||||
qse_word_t qse_stx_new_symbolx (
|
||||
qse_stx_t* stx, const qse_char_t* name, qse_word_t len)
|
||||
{
|
||||
qse_word_t capa, hash, index, size, x;
|
||||
|
||||
capa = stx->symtab.capacity;
|
||||
size = stx->symtab.size;
|
||||
|
||||
if (capa <= size + 1)
|
||||
{
|
||||
__grow_symtab (stx);
|
||||
capa = stx->symtab.capacity;
|
||||
}
|
||||
|
||||
hash = qse_stx_strxhash(name,len);
|
||||
index = hash % stx->symtab.capacity;
|
||||
|
||||
while (1)
|
||||
{
|
||||
x = stx->symtab.datum[index];
|
||||
if (x == stx->nil)
|
||||
{
|
||||
/* insert a new item into an empty slot */
|
||||
x = qse_stx_alloc_char_objectx (stx, name, len);
|
||||
QSE_STX_CLASS(stx,x) = stx->class_symbol;
|
||||
stx->symtab.datum[index] = x;
|
||||
stx->symtab.size++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (qse_strxncmp(name, len,
|
||||
QSE_STX_DATA(stx,x), QSE_STX_SIZE(stx,x)) == 0) break;
|
||||
|
||||
index = (index % stx->symtab.capacity) + 1;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
void qse_stx_traverse_symbol_table (
|
||||
qse_stx_t* stx, void (*func) (qse_stx_t*,qse_word_t,void*), void* data)
|
||||
{
|
||||
qse_word_t index, x;
|
||||
|
||||
for (index = 0; index < stx->symtab.capacity; index++)
|
||||
{
|
||||
x = stx->symtab.datum[index];
|
||||
if (x != stx->nil) func (stx, x, data);
|
||||
}
|
||||
}
|
||||
|
40
qse/lib/stx/symbol.h
Normal file
40
qse/lib/stx/symbol.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* $Id: symbol.h 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#ifndef _QSE_STX_SYMBOL_H_
|
||||
#define _QSE_STX_SYMBOL_H_
|
||||
|
||||
#include <qse/stx/stx.h>
|
||||
|
||||
#define QSE_STX_SYMLINK_SIZE 2
|
||||
#define QSE_STX_SYMLINK_LINK 0
|
||||
#define QSE_STX_SYMLINK_SYMBOL 1
|
||||
|
||||
struct qse_stx_symlink_t
|
||||
{
|
||||
qse_stx_objhdr_t header;
|
||||
qse_word_t link;
|
||||
qse_word_t symbol;
|
||||
};
|
||||
|
||||
typedef struct qse_stx_symlink_t qse_stx_symlink_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
qse_word_t qse_stx_new_symbol_link (qse_stx_t* stx, qse_word_t sym);
|
||||
|
||||
qse_word_t qse_stx_new_symbol (
|
||||
qse_stx_t* stx, const qse_char_t* name);
|
||||
qse_word_t qse_stx_new_symbolx (
|
||||
qse_stx_t* stx, const qse_char_t* name, qse_word_t len);
|
||||
void qse_stx_traverse_symbol_table (
|
||||
qse_stx_t* stx, void (*func) (qse_stx_t*,qse_word_t,void*), void* data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
77
qse/lib/stx/token.c
Normal file
77
qse/lib/stx/token.c
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* $Id: token.c 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#include <qse/stx/token.h>
|
||||
#include <qse/stx/misc.h>
|
||||
|
||||
qse_stx_token_t* qse_stx_token_open (
|
||||
qse_stx_token_t* token, qse_word_t capacity)
|
||||
{
|
||||
if (token == QSE_NULL) {
|
||||
token = (qse_stx_token_t*)
|
||||
qse_malloc (qse_sizeof(qse_stx_token_t));
|
||||
if (token == QSE_NULL) return QSE_NULL;
|
||||
token->__dynamic = qse_true;
|
||||
}
|
||||
else token->__dynamic = qse_false;
|
||||
|
||||
if (qse_stx_name_open(&token->name, capacity) == QSE_NULL) {
|
||||
if (token->__dynamic) qse_free (token);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
token->ivalue = 0;
|
||||
token->fvalue = .0;
|
||||
*/
|
||||
token->type = QSE_STX_TOKEN_END;
|
||||
return token;
|
||||
}
|
||||
|
||||
void qse_stx_token_close (qse_stx_token_t* token)
|
||||
{
|
||||
qse_stx_name_close (&token->name);
|
||||
if (token->__dynamic) qse_free (token);
|
||||
}
|
||||
|
||||
int qse_stx_token_addc (qse_stx_token_t* token, qse_cint_t c)
|
||||
{
|
||||
return qse_stx_name_addc (&token->name, c);
|
||||
}
|
||||
|
||||
int qse_stx_token_adds (qse_stx_token_t* token, const qse_char_t* s)
|
||||
{
|
||||
return qse_stx_name_adds (&token->name, s);
|
||||
}
|
||||
|
||||
void qse_stx_token_clear (qse_stx_token_t* token)
|
||||
{
|
||||
/*
|
||||
token->ivalue = 0;
|
||||
token->fvalue = .0;
|
||||
*/
|
||||
|
||||
token->type = QSE_STX_TOKEN_END;
|
||||
qse_stx_name_clear (&token->name);
|
||||
}
|
||||
|
||||
qse_char_t* qse_stx_token_yield (qse_stx_token_t* token, qse_word_t capacity)
|
||||
{
|
||||
qse_char_t* p;
|
||||
|
||||
p = qse_stx_name_yield (&token->name, capacity);
|
||||
if (p == QSE_NULL) return QSE_NULL;
|
||||
|
||||
/*
|
||||
token->ivalue = 0;
|
||||
token->fvalue = .0;
|
||||
*/
|
||||
token->type = QSE_STX_TOKEN_END;
|
||||
return p;
|
||||
}
|
||||
|
||||
int qse_stx_token_compare_name (qse_stx_token_t* token, const qse_char_t* str)
|
||||
{
|
||||
return qse_stx_name_compare (&token->name, str);
|
||||
}
|
66
qse/lib/stx/token.h
Normal file
66
qse/lib/stx/token.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* $Id: token.h 118 2008-03-03 11:21:33Z baconevi $
|
||||
*/
|
||||
|
||||
#ifndef _QSE_STX_TOKEN_H_
|
||||
#define _QSE_STX_TOKEN_H_
|
||||
|
||||
#include <qse/stx/stx.h>
|
||||
#include <qse/stx/name.h>
|
||||
|
||||
enum
|
||||
{
|
||||
QSE_STX_TOKEN_END,
|
||||
QSE_STX_TOKEN_CHARLIT,
|
||||
QSE_STX_TOKEN_STRLIT,
|
||||
QSE_STX_TOKEN_SYMLIT,
|
||||
QSE_STX_TOKEN_NUMLIT,
|
||||
QSE_STX_TOKEN_IDENT,
|
||||
QSE_STX_TOKEN_BINARY,
|
||||
QSE_STX_TOKEN_KEYWORD,
|
||||
QSE_STX_TOKEN_PRIMITIVE,
|
||||
QSE_STX_TOKEN_ASSIGN,
|
||||
QSE_STX_TOKEN_COLON,
|
||||
QSE_STX_TOKEN_RETURN,
|
||||
QSE_STX_TOKEN_LBRACKET,
|
||||
QSE_STX_TOKEN_RBRACKET,
|
||||
QSE_STX_TOKEN_LPAREN,
|
||||
QSE_STX_TOKEN_RPAREN,
|
||||
QSE_STX_TOKEN_APAREN,
|
||||
QSE_STX_TOKEN_PERIOD,
|
||||
QSE_STX_TOKEN_SEMICOLON
|
||||
};
|
||||
|
||||
struct qse_stx_token_t
|
||||
{
|
||||
int type;
|
||||
|
||||
/*
|
||||
qse_stx_int_t ivalue;
|
||||
qse_stx_real_t fvalue;
|
||||
*/
|
||||
qse_stx_name_t name;
|
||||
qse_bool_t __dynamic;
|
||||
};
|
||||
|
||||
typedef struct qse_stx_token_t qse_stx_token_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
qse_stx_token_t* qse_stx_token_open (
|
||||
qse_stx_token_t* token, qse_word_t capacity);
|
||||
void qse_stx_token_close (qse_stx_token_t* token);
|
||||
|
||||
int qse_stx_token_addc (qse_stx_token_t* token, qse_cint_t c);
|
||||
int qse_stx_token_adds (qse_stx_token_t* token, const qse_char_t* s);
|
||||
void qse_stx_token_clear (qse_stx_token_t* token);
|
||||
qse_char_t* qse_stx_token_yield (qse_stx_token_t* token, qse_word_t capacity);
|
||||
int qse_stx_token_compare_name (qse_stx_token_t* token, const qse_char_t* str);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user