2299 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			2299 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /*
 | ||
|  |  * $Id$ | ||
|  |  * | ||
|  |     Copyright (c) 2014-2015 Chung, Hyung-Hwan. All rights reserved. | ||
|  | 
 | ||
|  |     Redistribution and use in source and binary forms, with or without | ||
|  |     modification, are permitted provided that the following conditions | ||
|  |     are met: | ||
|  |     1. Redistributions of source code must retain the above copyright | ||
|  |        notice, this list of conditions and the following disclaimer. | ||
|  |     2. Redistributions in binary form must reproduce the above copyright | ||
|  |        notice, this list of conditions and the following disclaimer in the | ||
|  |        documentation and/or other materials provided with the distribution. | ||
|  | 
 | ||
|  |     THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR | ||
|  |     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
|  |     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
|  |     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
|  |     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
|  |     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
|  |     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
|  |     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
|  |     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
|  |     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
|  |  */ | ||
|  | 
 | ||
|  | #include "stix-prv.h"
 | ||
|  | 
 | ||
|  | #if 0
 | ||
|  | enum class_type_t | ||
|  | { | ||
|  | 	CLASS_NORMAL = 0, | ||
|  | 	CLASS_VARIABLE, | ||
|  | 	CLASS_VARIABLE_BYTE, | ||
|  | 	CLASS_VARIABLE_CHAR | ||
|  | }; | ||
|  | typedef enum class_type_t class_type_t; | ||
|  | 
 | ||
|  | enum vardef_type_t | ||
|  | { | ||
|  | 	VARDEF_INSTANCE, | ||
|  | 	VARDEF_CLASS_INSTANCE, | ||
|  | 	VARDEF_CLASS | ||
|  | }; | ||
|  | typedef enum vardef_type_t vardef_type_t; | ||
|  | 
 | ||
|  | enum stix_send_target_t | ||
|  | { | ||
|  | 	STIX_SELF = 0, | ||
|  | 	STIX_SUPER = 1 | ||
|  | }; | ||
|  | typedef enum stix_send_target_t stix_send_target_t; | ||
|  | 
 | ||
|  | enum stix_stack_operand_t | ||
|  | { | ||
|  | 	STIX_RECEIVER_VARIABLE = 0, | ||
|  | 	STIX_TEMPORARY_LOCATION = 1, | ||
|  | 	STIX_LITERAL_CONSTANT = 2, | ||
|  | 	STIX_LITERAL_VARIABLE = 3 | ||
|  | }; | ||
|  | typedef enum stix_stack_operand_t stix_stack_operand_t; | ||
|  | 
 | ||
|  | static void clear_sio_names (stix_t* fsc); | ||
|  | static int begin_include (stix_t* fsc); | ||
|  | static int end_include (stix_t* fsc); | ||
|  | 
 | ||
|  | stix_t* stix_open (stix_mmgr_t* mmgr, stix_size_t xtnsize, stix_size_t vmheapsize) | ||
|  | { | ||
|  | 	stix_t* fsc; | ||
|  | 
 | ||
|  | 	fsc = STIX_MMGR_ALLOC (mmgr, STIX_SIZEOF(*fsc) + xtnsize); | ||
|  | 	if (fsc) | ||
|  | 	{ | ||
|  | 		if (stix_init (fsc, mmgr, vmheapsize) <= -1) | ||
|  | 		{ | ||
|  | 			STIX_MMGR_FREE (mmgr, fsc); | ||
|  | 			fsc = STIX_NULL; | ||
|  | 		} | ||
|  | 		else STIX_MEMSET (fsc + 1, 0, xtnsize); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return fsc; | ||
|  | } | ||
|  | 
 | ||
|  | void stix_close (stix_t* fsc) | ||
|  | { | ||
|  | 	stix_fini (fsc); | ||
|  | 	STIX_MMGR_FREE (fsc->mmgr, fsc); | ||
|  | } | ||
|  | 
 | ||
|  | int stix_init (stix_t* fsc, stix_mmgr_t* mmgr, stix_size_t vmheapsize) | ||
|  | { | ||
|  | 	int trait; | ||
|  | 
 | ||
|  | 	STIX_MEMSET (fsc, 0, STIX_SIZEOF(*fsc)); | ||
|  | 	fsc->mmgr = mmgr; | ||
|  | 	fsc->errstr = stix_dflerrstr; | ||
|  | 
 | ||
|  | 	fsc->vm = stix_vm_open (mmgr, 0, vmheapsize); | ||
|  | 	if (fsc->vm == STIX_NULL)  | ||
|  | 	{ | ||
|  | 		fsc->errnum = STIX_FSC_ENOMEM; | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/* turn off garbage collection by force */ | ||
|  | 	stix_vm_getopt (fsc->vm, STIX_VM_TRAIT, &trait); | ||
|  | 	trait |= STIX_VM_NOGC; | ||
|  | 	stix_vm_setopt (fsc->vm, STIX_VM_TRAIT, &trait); | ||
|  | 
 | ||
|  | 	if (stix_vm_boom (fsc->vm) <= -1) | ||
|  | 	{ | ||
|  | 		/* TODO: translate vm error to fsc error */ | ||
|  | fsc->errnum = STIX_FSC_ENOMEM; | ||
|  | 		stix_vm_close (fsc->vm); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | #if 0
 | ||
|  | 	if (stix_tok_open (&fsc->tok, 0) == STIX_NULL)  | ||
|  | 	{ | ||
|  | 		if (fsc->__dynamic) stix_free (fsc); | ||
|  | 		return STIX_NULL; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (stix_arr_open ( | ||
|  | 		&fsc->bcd, 256,  | ||
|  | 		stix_sizeof(stix_uint8_t), STIX_NULL) == STIX_NULL)  | ||
|  | 	{ | ||
|  | 		stix_tok_close (&fsc->tok); | ||
|  | 		if (fsc->__dynamic) stix_free (fsc); | ||
|  | 		return STIX_NULL; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	fsc->stx = stx; | ||
|  | 	fsc->errnum = STIX_FSC_ERROR_NONE; | ||
|  | 
 | ||
|  | 	fsc->met.tmpr.count = 0; | ||
|  | 	fsc->met.tmpr.nargs = 0; | ||
|  | 	fsc->literal_count = 0; | ||
|  | 
 | ||
|  | 	fsc->sio.lxc.c = STIX_CHAR_EOF; | ||
|  | 	fsc->ungotc_count = 0; | ||
|  | 
 | ||
|  | 	fsc->input_owner = STIX_NULL; | ||
|  | 	fsc->input_func = STIX_NULL; | ||
|  | 	return fsc; | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | void stix_fini (stix_t* fsc) | ||
|  | { | ||
|  | 	stix_vm_close (fsc->vm); | ||
|  | 
 | ||
|  | #if 0
 | ||
|  | 	stix_arr_close (&fsc->bcd); | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 	clear_sio_names (fsc); | ||
|  | } | ||
|  | 
 | ||
|  | /* ---------------------------------------------------------------------
 | ||
|  |  * Tokenizer  | ||
|  |  * --------------------------------------------------------------------- */ | ||
|  | 
 | ||
|  | static STIX_INLINE int is_binselchar (stix_cint_t c) | ||
|  | { | ||
|  | 	/*
 | ||
|  | 	 * binarySelectorCharacter ::= | ||
|  | 	 * 	'!' | '%' | '&' | '*' | '+' | ',' |  | ||
|  | 	 * 	'/' | '<' | '>' | '=' | '?' | '@' |  | ||
|  | 	 * 	'\' | '~' | '|' | '-' | ||
|  | 	 */ | ||
|  | 
 | ||
|  | 	switch (c) | ||
|  | 	{ | ||
|  | 		case STIX_T('!'): | ||
|  | 		case STIX_T('%'): | ||
|  | 		case STIX_T('&'): | ||
|  | 		case STIX_T('*'): | ||
|  | 		case STIX_T('+'): | ||
|  | 		case STIX_T(','): | ||
|  | 		case STIX_T('/'):  | ||
|  | 		case STIX_T('<'): | ||
|  | 		case STIX_T('>'): | ||
|  | 		case STIX_T('='): | ||
|  | 		case STIX_T('?'): | ||
|  | 		case STIX_T('@'): | ||
|  | 		case STIX_T('\\'): | ||
|  | 		case STIX_T('|'): | ||
|  | 		case STIX_T('~'): | ||
|  | 		case STIX_T('-'): | ||
|  | 			return 1; | ||
|  | 		 | ||
|  | 		default: | ||
|  | 			return 0; | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | static STIX_INLINE int is_closing_char (stix_cint_t c) | ||
|  | { | ||
|  | 	return  | ||
|  | 		c == STIX_T('.') || c == STIX_T(']') || | ||
|  | 		c == STIX_T(')') || c == STIX_T(';') || | ||
|  | 		c == STIX_T('\"') || c == STIX_T('\''); | ||
|  | } | ||
|  | 
 | ||
|  | #define GET_CHAR(fsc) \
 | ||
|  | 	do { if (get_char (fsc) == -1) return -1; } while (0) | ||
|  | 
 | ||
|  | #define GET_TOKEN(fsc) \
 | ||
|  | 	do { if (get_token (fsc) == -1) return -1; } while (0) | ||
|  | 
 | ||
|  | #define ADD_TOKEN_CHAR(fsc,c) \
 | ||
|  | 	do { if (add_token_char (fsc, c) == -1) return -1; } while (0) | ||
|  | 
 | ||
|  | #define ADD_TOKEN_STR(fsc,s) \
 | ||
|  | 	do { if (add_token_str (fsc, s) == -1) return -1; } while (0) | ||
|  | 
 | ||
|  | static STIX_INLINE int add_token_char (stix_t* fsc, stix_char_t c) | ||
|  | { | ||
|  | 	if (fsc->tok.name.len >= STIX_COUNTOF(fsc->tok.buf) - 1) | ||
|  | 	{ | ||
|  | 		/* the tok buffer is full. cannot add more characters to it */ | ||
|  | 		fsc->errnum = STIX_FSC_ETOKTL; | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 	fsc->tok.buf[fsc->tok.name.len++] = c; | ||
|  | 	fsc->tok.buf[fsc->tok.name.len] = STIX_T('\0'); | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static STIX_INLINE int add_token_str (stix_t* fsc, const stix_char_t* str) | ||
|  | { | ||
|  | 	stix_size_t len; | ||
|  | 
 | ||
|  | 	len = stix_strlen (str); | ||
|  | 	if (fsc->tok.name.len + len >= STIX_COUNTOF(fsc->tok.buf) - 1) | ||
|  | 	{ | ||
|  | 		/* the tok buffer is full. cannot add more characters to it */ | ||
|  | 		fsc->errnum = STIX_FSC_ETOKTL; | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	fsc->tok.name.len += stix_strcpy (&fsc->tok.buf[fsc->tok.name.len], str); | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int get_char (stix_t* fsc) | ||
|  | { | ||
|  | 	stix_ssize_t n; | ||
|  | 
 | ||
|  | 	if (fsc->sio.inp->b.pos >= fsc->sio.inp->b.len) | ||
|  | 	{ | ||
|  | 		n = fsc->sio.impl (fsc, STIX_FSC_IO_READ, fsc->sio.inp); | ||
|  | 		if (n <= -1) return -1; | ||
|  | 
 | ||
|  | 		if (n == 0) | ||
|  | 		{ | ||
|  | 			fsc->sio.inp->lxc.c = STIX_CHAR_EOF; | ||
|  | 			fsc->sio.inp->lxc.line = fsc->sio.inp->line; | ||
|  | 			fsc->sio.inp->lxc.colm = fsc->sio.inp->colm; | ||
|  | 			fsc->sio.inp->lxc.file = fsc->sio.inp->name; | ||
|  | 			fsc->sio.lxc = fsc->sio.inp->lxc; | ||
|  | 			return 0; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		fsc->sio.inp->b.pos = 0; | ||
|  | 		fsc->sio.inp->b.len = n;	 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (fsc->sio.inp->lxc.c == STIX_T('\n')) | ||
|  | 	{ | ||
|  | 		/* if the previous charater was a newline,
 | ||
|  | 		 * increment the line counter and reset column to 1. | ||
|  | 		 * incrementing it line number here instead of | ||
|  | 		 * updating inp->lxc causes the line number for | ||
|  | 		 * TOK_EOF to be the same line as the lxc newline. */ | ||
|  | 		fsc->sio.inp->line++; | ||
|  | 		fsc->sio.inp->colm = 1; | ||
|  | 	} | ||
|  | 	 | ||
|  | 	fsc->sio.inp->lxc.c = fsc->sio.inp->buf[fsc->sio.inp->b.pos++]; | ||
|  | 	fsc->sio.inp->lxc.line = fsc->sio.inp->line; | ||
|  | 	fsc->sio.inp->lxc.colm = fsc->sio.inp->colm++; | ||
|  | 	fsc->sio.inp->lxc.file = fsc->sio.inp->name; | ||
|  | 	fsc->sio.lxc = fsc->sio.inp->lxc; | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int skip_spaces (stix_t* fsc) | ||
|  | { | ||
|  | 	while (STIX_ISSPACE(fsc->sio.lxc.c)) GET_CHAR (fsc); | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int skip_comment (stix_t* fsc) | ||
|  | { | ||
|  | 	/* comment is a double quoted string */ | ||
|  | 	while (fsc->sio.lxc.c != STIX_T('"')) GET_CHAR (fsc); | ||
|  | 	GET_CHAR (fsc); /* skip the closing quote */ | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int get_ident (stix_t* fsc) | ||
|  | { | ||
|  | 	/*
 | ||
|  | 	 * identifier ::= letter (letter | digit)* | ||
|  | 	 * keyword ::= identifier ':' | ||
|  | 	 */ | ||
|  | 
 | ||
|  | 	stix_cint_t c = fsc->sio.lxc.c; | ||
|  | 	fsc->tok.type = STIX_FSC_TOK_IDENT; | ||
|  | 
 | ||
|  | 	do  | ||
|  | 	{ | ||
|  | 		ADD_TOKEN_CHAR(fsc, c); | ||
|  | 		GET_CHAR (fsc); | ||
|  | 		c = fsc->sio.lxc.c; | ||
|  | 	}  | ||
|  | 	while (STIX_ISALPHA(c) || STIX_ISDIGIT(c)); | ||
|  | 
 | ||
|  | 	if (c == STIX_T(':'))  | ||
|  | 	{ | ||
|  | 		ADD_TOKEN_CHAR (fsc, c); | ||
|  | 		fsc->tok.type = STIX_FSC_TOK_KEYWORD; | ||
|  | 		GET_CHAR (fsc); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int get_numlit (stix_t* fsc, int negated) | ||
|  | { | ||
|  | 	/* 
 | ||
|  | 	 * <number literal> ::= ['-'] <number> | ||
|  | 	 * <number> ::= integer | float | scaledDecimal | ||
|  | 	 * integer ::= decimalInteger  | radixInteger | ||
|  | 	 * decimalInteger ::= digits | ||
|  | 	 * digits ::= digit+ | ||
|  | 	 * radixInteger ::= radixSpecifier  'r' radixDigits | ||
|  | 	 * radixSpecifier := digits | ||
|  | 	 * radixDigits ::= (digit | uppercaseAlphabetic)+ | ||
|  | 	 * float ::=  mantissa [exponentLetter exponent] | ||
|  | 	 * mantissa ::= digits'.' digits | ||
|  | 	 * exponent ::= ['-']decimalInteger | ||
|  | 	 * exponentLetter ::= 'e' | 'd' | 'q' | ||
|  | 	 * scaledDecimal ::= scaledMantissa 's' [fractionalDigits] | ||
|  | 	 * scaledMantissa ::= decimalInteger | mantissa | ||
|  | 	 * fractionalDigits ::= decimalInteger | ||
|  | 	 */ | ||
|  | 
 | ||
|  | 	stix_cint_t c = fsc->sio.lxc.c; | ||
|  | 	fsc->tok.type = STIX_FSC_TOK_NUMLIT; | ||
|  | 
 | ||
|  | 	do  | ||
|  | 	{ | ||
|  | 		ADD_TOKEN_CHAR(fsc, c); | ||
|  | 		GET_CHAR (fsc); | ||
|  | 		c = fsc->sio.lxc.c; | ||
|  | 	}  | ||
|  | 	while (STIX_ISALPHA(c) || STIX_ISDIGIT(c)); | ||
|  | 
 | ||
|  | 	/* TODO; more */ | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int get_charlit (stix_t* fsc) | ||
|  | { | ||
|  | 	/* 
 | ||
|  | 	 * character_literal ::= '$' character | ||
|  | 	 * character ::= "Any character in the implementation-defined character set" | ||
|  | 	 */ | ||
|  | 
 | ||
|  | 	stix_cint_t c = fsc->sio.lxc.c; /* even a new-line or white space would be taken */ | ||
|  | 	if (c == STIX_CHAR_EOF)  | ||
|  | 	{ | ||
|  | 		stix_seterrnum (fsc, STIX_FSC_ECHRNT, STIX_NULL); | ||
|  | 		return -1; | ||
|  | 	}	 | ||
|  | 
 | ||
|  | 	fsc->tok.type = STIX_FSC_TOK_CHRLIT; | ||
|  | 	ADD_TOKEN_CHAR(fsc, c); | ||
|  | 	GET_CHAR (fsc); | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int get_strlit (stix_t* fsc) | ||
|  | { | ||
|  | 	/* 
 | ||
|  | 	 * string_literal ::= stringDelimiter stringBody stringDelimiter | ||
|  | 	 * stringBody ::= (nonStringDelimiter | (stringDelimiter stringDelimiter)*) | ||
|  | 	 * stringDelimiter ::= '''    "a single quote" | ||
|  | 	 */ | ||
|  | 
 | ||
|  | 	/* TODO: C-like string */ | ||
|  | 
 | ||
|  | 	stix_cint_t c = fsc->sio.lxc.c; | ||
|  | 	fsc->tok.type = STIX_FSC_TOK_STRLIT; | ||
|  | 
 | ||
|  | 	do  | ||
|  | 	{ | ||
|  | 		do  | ||
|  | 		{ | ||
|  | 			ADD_TOKEN_CHAR (fsc, c); | ||
|  | 			GET_CHAR (fsc); | ||
|  | 			c = fsc->sio.lxc.c; | ||
|  | 
 | ||
|  | 			if (c == STIX_CHAR_EOF)  | ||
|  | 			{ | ||
|  | 				stix_seterrnum (fsc, STIX_FSC_ESTRNT, STIX_NULL); | ||
|  | 				return -1; | ||
|  | 			} | ||
|  | 		}  | ||
|  | 		while (c != STIX_T('\'')); | ||
|  | 
 | ||
|  | 		GET_CHAR (fsc); | ||
|  | 		c = fsc->sio.lxc.c; | ||
|  | 	}  | ||
|  | 	while (c == STIX_T('\'')); | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int get_binsel (stix_t* fsc) | ||
|  | { | ||
|  | 	/* 
 | ||
|  | 	 * binarySelector ::= binarySelectorCharacter+ | ||
|  | 	 */ | ||
|  | 
 | ||
|  | 	ADD_TOKEN_CHAR (fsc, fsc->sio.lxc.c); | ||
|  | 
 | ||
|  | 	if (fsc->sio.lxc.c == STIX_T('-'))  | ||
|  | 	{ | ||
|  | 		/* special case if a minus is followed by a digit immediately */ | ||
|  | 		GET_CHAR (fsc); | ||
|  | 		if (STIX_ISDIGIT(fsc->sio.lxc.c)) return get_numlit (fsc, 1); | ||
|  | 	} | ||
|  | 	else GET_CHAR (fsc); | ||
|  | 
 | ||
|  | 	/* up to 2 characters only */ | ||
|  | 	if (is_binselchar (fsc->sio.lxc.c))  | ||
|  | 	{ | ||
|  | 		ADD_TOKEN_CHAR (fsc, fsc->sio.lxc.c); | ||
|  | 		GET_CHAR (fsc); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/* or up to any occurrences */ | ||
|  | 	/*
 | ||
|  | 	while (is_binselchar(fsc->sio.lxc.c))  | ||
|  | 	{ | ||
|  | 		ADD_TOKEN_CHAR (fsc, c); | ||
|  | 		GET_CHAR (fsc); | ||
|  | 	} | ||
|  | 	*/ | ||
|  | 
 | ||
|  | 	fsc->tok.type = STIX_FSC_TOK_BINSEL; | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int get_token (stix_t* fsc) | ||
|  | { | ||
|  | 	stix_cint_t c; | ||
|  | 
 | ||
|  | retry: | ||
|  | 	do  | ||
|  | 	{ | ||
|  | 		if (skip_spaces(fsc) <= -1) return -1; | ||
|  | 		if (fsc->sio.lxc.c != STIX_T('"')) break; | ||
|  | 
 | ||
|  | 		GET_CHAR (fsc); | ||
|  | 		if (skip_comment(fsc) <= -1) return -1; | ||
|  | 	}  | ||
|  | 	while (1); | ||
|  | 
 | ||
|  | 	/* clear the token resetting its location */ | ||
|  | 	fsc->tok.type = 0;  | ||
|  | 	fsc->tok.buf[0] = STIX_T('\0');  | ||
|  | 	fsc->tok.name.len = 0; | ||
|  | 	fsc->tok.name.ptr = fsc->tok.buf; | ||
|  | 	fsc->tok.loc.file = fsc->sio.lxc.file; | ||
|  | 	fsc->tok.loc.line = fsc->sio.lxc.line; | ||
|  | 	fsc->tok.loc.colm = fsc->sio.lxc.colm; | ||
|  | 	c = fsc->sio.lxc.c; | ||
|  | 
 | ||
|  | 	switch (c) | ||
|  | 	{ | ||
|  | 		case STIX_CHAR_EOF: | ||
|  | 		{ | ||
|  | 			int n; | ||
|  | 
 | ||
|  | 			n = end_include (fsc); | ||
|  | 			if (n <= -1) return -1; | ||
|  | 			if (n >= 1) goto retry; | ||
|  | 
 | ||
|  | 			fsc->tok.type = STIX_FSC_TOK_EOF; | ||
|  | 			ADD_TOKEN_STR(fsc, STIX_T("<EOF>")); | ||
|  | 			break; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		case STIX_T('$'): /* character literal */ | ||
|  | 			GET_CHAR (fsc); | ||
|  | 			if (get_charlit(fsc) == -1) return -1; | ||
|  | 			break; | ||
|  | 
 | ||
|  | 		case STIX_T('\''): /* string literal */ | ||
|  | 			GET_CHAR (fsc); | ||
|  | 			if (get_strlit(fsc) == -1) return -1; | ||
|  | 			break; | ||
|  | 
 | ||
|  | 		case STIX_T(':'): | ||
|  | 			fsc->tok.type = STIX_FSC_TOK_COLON; | ||
|  | 			ADD_TOKEN_CHAR(fsc, c); | ||
|  | 			GET_CHAR (fsc); | ||
|  | 
 | ||
|  | 			c = fsc->sio.lxc.c; | ||
|  | 			if (c == STIX_T('='))  | ||
|  | 			{ | ||
|  | 				fsc->tok.type = STIX_FSC_TOK_ASSIGN; | ||
|  | 				ADD_TOKEN_CHAR(fsc, c); | ||
|  | 				GET_CHAR (fsc); | ||
|  | 			} | ||
|  | 			break; | ||
|  | 
 | ||
|  | 		case STIX_T('^'): | ||
|  | 		case STIX_T('{'): /* extension */ | ||
|  | 		case STIX_T('}'): /* extension */ | ||
|  | 		case STIX_T('['): | ||
|  | 		case STIX_T(']'):  | ||
|  | 		case STIX_T('('): | ||
|  | 		case STIX_T(')'): | ||
|  | 		case STIX_T('.'): | ||
|  | 		case STIX_T(';'): | ||
|  | 		case STIX_T('#'): | ||
|  | 			switch (c)  | ||
|  | 			{ | ||
|  | 				case STIX_T('^'): | ||
|  | 					fsc->tok.type = STIX_FSC_TOK_RETURN; | ||
|  | 					break; | ||
|  | 
 | ||
|  | 				case STIX_T('{'): | ||
|  | 					fsc->tok.type = STIX_FSC_TOK_LBRACE; | ||
|  | 					break; | ||
|  | 		 | ||
|  | 				case STIX_T('}'):  | ||
|  | 					fsc->tok.type = STIX_FSC_TOK_RBRACE; | ||
|  | 					break; | ||
|  | 		 | ||
|  | 				case STIX_T('['): | ||
|  | 					fsc->tok.type = STIX_FSC_TOK_LBRACK; | ||
|  | 					break; | ||
|  | 		 | ||
|  | 				case STIX_T(']'):  | ||
|  | 					fsc->tok.type = STIX_FSC_TOK_RBRACK; | ||
|  | 					break; | ||
|  | 
 | ||
|  | 				case STIX_T('('): | ||
|  | 					fsc->tok.type = STIX_FSC_TOK_LPAREN; | ||
|  | 					break; | ||
|  | 		 | ||
|  | 				case STIX_T(')'): | ||
|  | 					fsc->tok.type = STIX_FSC_TOK_RPAREN; | ||
|  | 					break; | ||
|  | 
 | ||
|  | 				case STIX_T('.'): | ||
|  | 					fsc->tok.type = STIX_FSC_TOK_PERIOD; | ||
|  | 					break; | ||
|  | 		 | ||
|  | 				case STIX_T(';'): | ||
|  | 					fsc->tok.type = STIX_FSC_TOK_SEMICOLON; | ||
|  | 					break; | ||
|  | 
 | ||
|  | 				case STIX_T('#'): | ||
|  | 					fsc->tok.type = STIX_FSC_TOK_HASH; | ||
|  | 					break; | ||
|  | 			} | ||
|  | 
 | ||
|  | 			ADD_TOKEN_CHAR(fsc, c); | ||
|  | 			GET_CHAR (fsc); | ||
|  | 			break; | ||
|  | 
 | ||
|  | #if 0
 | ||
|  | 		case STIX_T('#'):   | ||
|  | 			/*ADD_TOKEN_CHAR(fsc, c);*/ | ||
|  | 			GET_CHAR (fsc); | ||
|  | 
 | ||
|  | 			c = fsc->sio.lxc.c; | ||
|  | 			switch (c) | ||
|  | 			{ | ||
|  | 				case STIX_CHAR_EOF: | ||
|  | 					fsc->errnum = STIX_FSC_ELITNT; | ||
|  | 					return -1; | ||
|  | 				 | ||
|  | 				case STIX_T('('): | ||
|  | 					/* #( */ | ||
|  | 					ADD_TOKEN_CHAR(fsc, c); | ||
|  | 					fsc->tok.type = STIX_FSC_TOK_APAREN; | ||
|  | 					GET_CHAR (fsc); | ||
|  | 					break; | ||
|  | 
 | ||
|  | 				case STIX_T('\''): | ||
|  | 					/* #' - quoted symbol literal */ | ||
|  | 					GET_CHAR (fsc); | ||
|  | 					if (get_strlit(fsc) <= -1) return -1; | ||
|  | 					fsc->tok.type = STIX_FSC_TOK_SYMLIT; | ||
|  | 					break; | ||
|  | 
 | ||
|  | 				case STIX_T('['): | ||
|  | 					/* #[ - byte array literal */ | ||
|  | 					/* TODO */ | ||
|  | 					break; | ||
|  | 
 | ||
|  | 				default: | ||
|  | 					/* unquoted symbol literal */ | ||
|  | 					if (is_closing_char(c) || STIX_ISSPACE(c)) | ||
|  | 					{ | ||
|  | 						fsc->errnum = STIX_FSC_ELITNT; | ||
|  | 						return -1; | ||
|  | 					} | ||
|  | 
 | ||
|  | 					do  | ||
|  | 					{ | ||
|  | 						ADD_TOKEN_CHAR(fsc, c); | ||
|  | 						GET_CHAR (fsc); | ||
|  | 						c = fsc->sio.lxc.c; | ||
|  | 					}  | ||
|  | 					while (!is_closing_char(c) && !STIX_ISSPACE(c)); | ||
|  | 
 | ||
|  | 					fsc->tok.type = STIX_FSC_TOK_SYMLIT; | ||
|  | 					break; | ||
|  | 			} | ||
|  | 				 | ||
|  | 			break; | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 				 | ||
|  | 		default: | ||
|  | 			if (STIX_ISALPHA (c))  | ||
|  | 			{ | ||
|  | 				if (get_ident (fsc) <= -1) return -1; | ||
|  | 			} | ||
|  | 			else if (STIX_ISDIGIT (c))  | ||
|  | 			{ | ||
|  | 				if (get_numlit (fsc, 0) <= -1) return -1; | ||
|  | 			} | ||
|  | 			else if (is_binselchar (c))  | ||
|  | 			{ | ||
|  | 				/* binary selector */ | ||
|  | 				if (get_binsel (fsc) <= -1) return -1; | ||
|  | 			} | ||
|  | 			else  | ||
|  | 			{ | ||
|  | 				stix_cstr_t ea; | ||
|  | 				stix_char_t cc; | ||
|  | 
 | ||
|  | 				cc = (stix_char_t)c; | ||
|  | 				ea.ptr = &cc; | ||
|  | 				ea.len = 1; | ||
|  | 
 | ||
|  | 				stix_seterrnum (fsc, STIX_FSC_EILCHR, &ea); | ||
|  | 				return -1; | ||
|  | 			} | ||
|  | 			break; | ||
|  | 	} | ||
|  | 
 | ||
|  | wprintf (L"TOK: %S\n", fsc->tok.name.ptr); | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static void clear_sio_names (stix_t* fsc) | ||
|  | { | ||
|  | 	stix_link_t* cur; | ||
|  | 	while (fsc->sio_names) | ||
|  | 	{ | ||
|  | 		cur = fsc->sio_names; | ||
|  | 		fsc->sio_names = cur->link; | ||
|  | 		stix_freemem (fsc, cur); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | static int begin_include (stix_t* fsc) | ||
|  | { | ||
|  | 	stix_ioarg_t* arg; | ||
|  | 	stix_link_t* link; | ||
|  | 
 | ||
|  | 	link = (stix_link_t*) stix_callocmem (fsc, STIX_SIZEOF(*link) + STIX_SIZEOF(stix_char_t) * (fsc->tok.name.len + 1)); | ||
|  | 	if (link == STIX_NULL) goto oops; | ||
|  | 
 | ||
|  | 	stix_strcpy ((stix_char_t*)(link + 1), fsc->tok.name.ptr);  | ||
|  | 	link->link = fsc->sio_names; | ||
|  | 	fsc->sio_names = link; | ||
|  | 
 | ||
|  | 	arg = (stix_ioarg_t*) stix_callocmem (fsc, STIX_SIZEOF(*arg)); | ||
|  | 	if (arg == STIX_NULL) goto oops; | ||
|  | 
 | ||
|  | 	arg->name = (const stix_char_t*)(link + 1); | ||
|  | 	arg->line = 1; | ||
|  | 	arg->colm = 1; | ||
|  | 	arg->prev = fsc->sio.inp; | ||
|  | 
 | ||
|  | 	if (fsc->sio.impl (fsc, STIX_FSC_IO_OPEN, arg) <= -1) goto oops; | ||
|  | 
 | ||
|  | 	fsc->sio.inp = arg; | ||
|  | 	/* fsc->parse.depth.incl++; */ | ||
|  | 
 | ||
|  | 	/* read in the first character in the included file. 
 | ||
|  | 	 * so the next call to get_token() sees the character read | ||
|  | 	 * from this file. */ | ||
|  | 	if (get_char (fsc) <= -1 || get_token (fsc) <= -1)  | ||
|  | 	{ | ||
|  | 		end_include (fsc);  | ||
|  | 		/* i don't jump to oops since i've called 
 | ||
|  | 		 * end_include() where fsc->sio.inp/arg is freed. */ | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | 
 | ||
|  | oops: | ||
|  | 	/* i don't need to free 'link' since it's linked to
 | ||
|  | 	 * fsc->sio_names that's freed at the beginning of stix_read() | ||
|  | 	 * or by stix_fini() */ | ||
|  | 	if (arg) stix_freemem (fsc, arg); | ||
|  | 	return -1; | ||
|  | } | ||
|  | 
 | ||
|  | static int end_include (stix_t* fsc) | ||
|  | { | ||
|  | 	int x; | ||
|  | 	stix_ioarg_t* cur; | ||
|  | 
 | ||
|  | 	if (fsc->sio.inp == &fsc->sio.arg) return 0; /* no include */ | ||
|  | 
 | ||
|  | 	/* if it is an included file, close it and
 | ||
|  | 	 * retry to read a character from an outer file */ | ||
|  | 
 | ||
|  | 	x = fsc->sio.impl (fsc, STIX_FSC_IO_CLOSE, fsc->sio.inp); | ||
|  | 
 | ||
|  | 	/* if closing has failed, still destroy the
 | ||
|  | 	 * sio structure first as normal and return | ||
|  | 	 * the failure below. this way, the caller  | ||
|  | 	 * does not call STIX_FSC_SIO_CLOSE on  | ||
|  | 	 * fsc->sio.inp again. */ | ||
|  | 
 | ||
|  | 	cur = fsc->sio.inp; | ||
|  | 	fsc->sio.inp = fsc->sio.inp->prev; | ||
|  | 
 | ||
|  | 	STIX_ASSERT (cur->name != STIX_NULL); | ||
|  | 	stix_freemem (fsc, cur); | ||
|  | 	/* fsc->parse.depth.incl--; */ | ||
|  | 
 | ||
|  | 	if (x != 0) | ||
|  | 	{ | ||
|  | 		/* the failure mentioned above is returned here */ | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	fsc->sio.lxc = fsc->sio.inp->lxc; | ||
|  | 	return 1; /* ended the included file successfully */ | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* ---------------------------------------------------------------------
 | ||
|  |  * Parser and Code Generator  | ||
|  |  * --------------------------------------------------------------------- */ | ||
|  | 
 | ||
|  | static STIX_INLINE int is_tok_pseudovar (stix_t* fsc) | ||
|  | { | ||
|  | 	return fsc->tok.type == STIX_FSC_TOK_IDENT && | ||
|  | 	       (stix_strequal(fsc->tok.name.ptr, STIX_T("self")) || | ||
|  | 	        stix_strequal(fsc->tok.name.ptr, STIX_T("super")) || | ||
|  | 	        stix_strequal(fsc->tok.name.ptr, STIX_T("thisContext")) || | ||
|  | 	        stix_strequal(fsc->tok.name.ptr, STIX_T("nil")) || | ||
|  | 	        stix_strequal(fsc->tok.name.ptr, STIX_T("true")) || | ||
|  | 	        stix_strequal(fsc->tok.name.ptr, STIX_T("false"))); | ||
|  | } | ||
|  | 
 | ||
|  | static STIX_INLINE int is_tok_binsel (stix_t* fsc, const stix_char_t* sel) | ||
|  | { | ||
|  | 	return fsc->tok.type == STIX_FSC_TOK_BINSEL &&  | ||
|  | 	       stix_strequal (fsc->tok.name.ptr, sel); | ||
|  | } | ||
|  | 
 | ||
|  | #if 0
 | ||
|  | 
 | ||
|  | #define EMIT_CODE_TEST(fsc,high,low) \
 | ||
|  | 	do { if (emit_code_test(fsc,high,low) == -1) return -1; } while (0) | ||
|  | 
 | ||
|  | #define EMIT_PUSH_RECEIVER_VARIABLE(fsc,pos) \
 | ||
|  | 	do {  \ | ||
|  | 		if (emit_stack_positional ( \ | ||
|  | 			fsc, PUSH_RECEIVER_VARIABLE, pos) == -1) return -1; \ | ||
|  | 	} while (0) | ||
|  | 
 | ||
|  | #define EMIT_PUSH_TEMPORARY_LOCATION(fsc,pos) \
 | ||
|  | 	do {  \ | ||
|  | 		if (emit_stack_positional ( \ | ||
|  | 			fsc, PUSH_TEMPORARY_LOCATION, pos) == -1) return -1; \ | ||
|  | 	} while (0) | ||
|  | 
 | ||
|  | #define EMIT_PUSH_LITERAL_CONSTANT(fsc,pos) \
 | ||
|  | 	do { \ | ||
|  | 		if (emit_stack_positional ( \ | ||
|  | 			fsc, PUSH_LITERAL_CONSTANT, pos) == -1) return -1; \ | ||
|  | 	} while (0) | ||
|  | 
 | ||
|  | 
 | ||
|  | #define EMIT_PUSH_LITERAL_VARIABLE(fsc,pos) \
 | ||
|  | 	do { \ | ||
|  | 		if (emit_stack_positional ( \ | ||
|  | 			fsc, PUSH_LITERAL_VARIABLE, pos) == -1) return -1; \ | ||
|  | 	} while (0) | ||
|  | 
 | ||
|  | #define EMIT_STORE_RECEIVER_VARIABLE(fsc,pos) \
 | ||
|  | 	do { \ | ||
|  | 		if (emit_stack_positional ( \ | ||
|  | 			fsc, STORE_RECEIVER_VARIABLE, pos) == -1) return -1; \ | ||
|  | 	} while (0)	 | ||
|  | 
 | ||
|  | #define EMIT_STORE_TEMPORARY_LOCATION(fsc,pos) \
 | ||
|  | 	do { \ | ||
|  | 		if (emit_stack_positional ( \ | ||
|  | 			fsc, STORE_TEMPORARY_LOCATION, pos) == -1) return -1; \ | ||
|  | 	} while (0) | ||
|  | 
 | ||
|  | 
 | ||
|  | #define EMIT_POP_STACK_TOP(fsc) EMIT_CODE(fsc, POP_STACK_TOP)
 | ||
|  | #define EMIT_DUPLICATE_STACK_TOP(fsc) EMIT_CODE(fsc, DUPLICATE_STACK_TOP)
 | ||
|  | #define EMIT_PUSH_ACTIVE_CONTEXT(fsc) EMIT_CODE(fsc, PUSH_ACTIVE_CONTEXT)
 | ||
|  | #define EMIT_RETURN_FROM_MESSAGE(fsc) EMIT_CODE(fsc, RETURN_FROM_MESSAGE)
 | ||
|  | #define EMIT_RETURN_FROM_BLOCK(fsc) EMIT_CODE(fsc, RETURN_FROM_BLOCK)
 | ||
|  | 
 | ||
|  | #define EMIT_SEND_TO_SELF(fsc,nargs,selector) \
 | ||
|  | 	do { \ | ||
|  | 		if (emit_send_to_self(fsc,nargs,selector) == -1) return -1; \ | ||
|  | 	} while (0) | ||
|  | 
 | ||
|  | #define EMIT_SEND_TO_SUPER(fsc,nargs,selector) \
 | ||
|  | 	do { \ | ||
|  | 		if (emit_send_to_super(fsc,nargs,selector) == -1) return -1; \ | ||
|  | 	} while (0) | ||
|  | 
 | ||
|  | #define EMIT_DO_PRIMITIVE(fsc,no) \
 | ||
|  | 	do { if (emit_do_primitive(fsc,no) == -1) return -1; } while(0) | ||
|  | 
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | static STIX_INLINE int emit_code_test ( | ||
|  | 	stix_t* fsc, const stix_char_t* high, const stix_char_t* low) | ||
|  | { | ||
|  | wprintf (L"CODE: %s %s\n", high, low); | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static STIX_INLINE int emit_code (stix_t* fsc, const stix_uint8_t* code, int len) | ||
|  | { | ||
|  | 	int i; | ||
|  | 
 | ||
|  | 	if ((fsc->bcd.len + len) > STIX_COUNTOF(fsc->bcd.buf)) | ||
|  | 	{ | ||
|  | 		stix_seterrnum (fsc, STIX_FSC_EBCDTL, STIX_NULL); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	for (i = 0; i < len; i++) fsc->bcd.buf[fsc->bcd.len++] = code[i]; | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int emit_push_stack (stix_t* fsc, stix_stack_operand_t type, int pos) | ||
|  | { | ||
|  | 	/*
 | ||
|  | 	 * 0-15      0000iiii           Push Receiver Variable #iiii  | ||
|  | 	 * 16-31     0001iiii           Push Temporary Location #iiii | ||
|  | 	 * 32-63     001iiiii           Push Literal Constant #iiiii | ||
|  | 	 * 64-95     010iiiii           Push Literal Variable #iiiii | ||
|  | 	 * 128       10000000 jjkkkkkk  Push (Receiver Variable, Temporary Location, Literal Constant, Literal Variable) [jj] #kkkkkk | ||
|  | 	 */ | ||
|  | 
 | ||
|  | 	static int bcds[] =  | ||
|  | 	{ | ||
|  | 		STIX_PUSH_RECEIVER_VARIABLE, | ||
|  | 		STIX_PUSH_TEMPORARY_LOCATION, | ||
|  | 		STIX_PUSH_LITERAL_CONSTANT, | ||
|  | 		STIX_PUSH_LITERAL_VARIABLE  | ||
|  | 	}; | ||
|  | 	static int bounds[] = { 0x0F, 0x0F, 0x1F, 0x1F }; | ||
|  | 
 | ||
|  | 	stix_uint8_t code[2]; | ||
|  | 	int len = 0; | ||
|  | 
 | ||
|  | 	STIX_ASSERT (pos >= 0x0 &&  pos <= 0x3F); /* 0 to 63 */ | ||
|  | 	STIX_ASSERT (type >= STIX_RECEIVER_VARIABLE && type <= STIX_LITERAL_VARIABLE); | ||
|  | 
 | ||
|  | 	if (pos <= bounds[type]) | ||
|  | 	{ | ||
|  | 		code[len++] = bcds[type] | pos; | ||
|  | 	} | ||
|  | 	else | ||
|  | 	{ | ||
|  | 		code[len++] = STIX_PUSH_EXTENDED; | ||
|  | 		code[len++] = (type << 6)  | pos; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return emit_code (fsc, code, len); | ||
|  | } | ||
|  | 
 | ||
|  | static int emit_store_stack (stix_t* fsc, stix_stack_operand_t type, int pos) | ||
|  | { | ||
|  | 	/*
 | ||
|  | 	 * 129       10000001 jjkkkkkk  Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk | ||
|  | 	 */ | ||
|  | 
 | ||
|  | 	stix_uint8_t code[2]; | ||
|  | 	int len = 0; | ||
|  | 
 | ||
|  | 	STIX_ASSERT (pos >= 0x0 &&  pos <= 0x3F); /* 0 to 63 */ | ||
|  | 	STIX_ASSERT (type >= STIX_RECEIVER_VARIABLE && type <= STIX_LITERAL_VARIABLE); | ||
|  | 
 | ||
|  | 	code[len++] = STIX_STORE_EXTENDED; | ||
|  | 	code[len++] = (type << 6) | pos; | ||
|  | 
 | ||
|  | 	return emit_code (fsc, code, len); | ||
|  | } | ||
|  | 
 | ||
|  | static int emit_pop_store_stack (stix_t* fsc, stix_stack_operand_t type, int pos) | ||
|  | { | ||
|  | 	/*
 | ||
|  | 	 * 96-103    01100iii           Pop and Store Receiver Variable #iii | ||
|  | 	 * 104-111   01101iii           Pop and Store Temporary Location #iii | ||
|  | 	 * 129       10000001 jjkkkkkk  Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk | ||
|  | 	 * 130       10000010 jjkkkkkk  Pop and Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk | ||
|  | 	 */ | ||
|  | 
 | ||
|  | 	stix_uint8_t code[2]; | ||
|  | 	int len = 0; | ||
|  | 
 | ||
|  | 	static int bcds[] =  | ||
|  | 	{ | ||
|  | 		STIX_POP_STORE_RECEIVER_VARIABLE, | ||
|  | 		STIX_POP_STORE_TEMPORARY_LOCATION | ||
|  | 	}; | ||
|  | 
 | ||
|  | 	STIX_ASSERT (pos >= 0x0 &&  pos <= 0x3F); /* 0 to 63 */ | ||
|  | 	STIX_ASSERT (type >= STIX_RECEIVER_VARIABLE && type <= STIX_LITERAL_VARIABLE && type != STIX_LITERAL_CONSTANT); | ||
|  | 
 | ||
|  | 	switch (type) | ||
|  | 	{ | ||
|  | 		case STIX_RECEIVER_VARIABLE: | ||
|  | 		case STIX_TEMPORARY_LOCATION: | ||
|  | 			if (pos <= 0x07)  | ||
|  | 			{ | ||
|  | 				code[len++] = bcds[type] | pos; | ||
|  | 				break; | ||
|  | 			} | ||
|  | 			/* fall through */ | ||
|  | 
 | ||
|  | 		default: | ||
|  | 			code[len++] = STIX_POP_STORE_EXTENDED; | ||
|  | 			code[len++] = (type << 6)  | pos; | ||
|  | 			break; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return emit_code (fsc, code, len); | ||
|  | } | ||
|  | 
 | ||
|  | static int emit_send_message (stix_t* fsc, stix_send_target_t target, int selector, int nargs) | ||
|  | { | ||
|  | 	/*
 | ||
|  | 	 * 131       10000011 jjjkkkkk          Send Literal Selector #kkkkk With jjj Arguments | ||
|  | 	 * 132       10000100 jjjjjjjj kkkkkkkk Send Literal Selector #kkkkkkkk With jjjjjjjj Arguments | ||
|  | 	 * 133       10000101 jjjkkkkk          Send Literal Selector #kkkkk To Superclass With jjj Arguments | ||
|  | 	 * 134       10000110 jjjjjjjj kkkkkkkk Send Literal Selector #kkkkkkkk To Superclass With jjjjjjjj Arguments | ||
|  | 	 */ | ||
|  | 
 | ||
|  | 	static struct { int basic; int extended; } bcds[] = | ||
|  | 	{ | ||
|  | 		{ STIX_SEND_TO_SELF, STIX_SEND_TO_SELF_EXTENDED }, | ||
|  | 		{ STIX_SEND_TO_SUPER, STIX_SEND_TO_SUPER_EXTENDED } | ||
|  | 	}; | ||
|  | 
 | ||
|  | 	stix_uint8_t code[3]; | ||
|  | 	int len = 0; | ||
|  | 
 | ||
|  | 	STIX_ASSERT (selector >= 0 && selector <= 0xFF); | ||
|  | 	STIX_ASSERT (nargs >= 0 && nargs <= 0xFF); | ||
|  | 
 | ||
|  | 	if (nargs <= 0x7 && selector <= 0x1F) | ||
|  | 	{ | ||
|  | 		code[len++] = bcds[target].basic; | ||
|  | 		code[len++] = (nargs << 5) | selector; | ||
|  | 	} | ||
|  | 	else | ||
|  | 	{ | ||
|  | 		code[len++] = bcds[target].extended; | ||
|  | 		code[len++] = nargs; | ||
|  | 		code[len++] = selector; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return emit_code (fsc, code, len); | ||
|  | } | ||
|  | 
 | ||
|  | static int emit_do_primitive (stix_t* fsc, int no) | ||
|  | { | ||
|  | 	stix_uint8_t code[2]; | ||
|  | 	int len = 0; | ||
|  | 
 | ||
|  | 	STIX_ASSERT (no >= 0x0 && no <= 0xFF); | ||
|  | 
 | ||
|  | 	code[len++] = STIX_DO_PRIMITIVE; | ||
|  | 	code[len++] = no; | ||
|  | 
 | ||
|  | 	return emit_code (fsc, code, len); | ||
|  | } | ||
|  | 
 | ||
|  | #if 0
 | ||
|  | static int __add_literal (stix_t* fsc, stix_word_t literal) | ||
|  | { | ||
|  | 	stix_word_t i; | ||
|  | 
 | ||
|  | 	for (i = 0; i < fsc->literal_count; i++) { | ||
|  | 		/* 
 | ||
|  | 		 * it would remove redundancy of symbols and small integers.  | ||
|  | 		 * more complex redundacy check may be done somewhere else  | ||
|  | 		 * like in __add_string_literal. | ||
|  | 		 */ | ||
|  | 		if (fsc->literals[i] == literal) return i; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (fsc->literal_count >= STIX_COUNTOF(fsc->literals)) { | ||
|  | 		fsc->errnum = STIX_FSC_ERROR_TOO_MANY_LITERALS; | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	fsc->literals[fsc->literal_count++] = literal; | ||
|  | 	return fsc->literal_count - 1; | ||
|  | } | ||
|  | 
 | ||
|  | static int __add_character_literal (stix_t* fsc, stix_char_t ch) | ||
|  | { | ||
|  | 	stix_word_t i, c, literal; | ||
|  | 	stix_vm_t* stx = fsc->stx; | ||
|  | 
 | ||
|  | 	for (i = 0; i < fsc->literal_count; i++) { | ||
|  | 		c = STIX_ISSMALLINT(fsc->literals[i])?  | ||
|  | 			stx->class_smallinteger: STIX_CLASS (stx, fsc->literals[i]); | ||
|  | 		if (c != stx->class_character) continue; | ||
|  | 
 | ||
|  | 		if (ch == STIX_CHAR_AT(stx,fsc->literals[i],0)) return i; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	literal = stix_instantiate ( | ||
|  | 		stx, stx->class_character, &ch, STIX_NULL, 0); | ||
|  | 	return __add_literal (fsc, literal); | ||
|  | } | ||
|  | 
 | ||
|  | static int __add_string_literal ( | ||
|  | 	stix_t* fsc, const stix_char_t* str, stix_word_t size) | ||
|  | { | ||
|  | 	stix_word_t i, c, literal; | ||
|  | 	stix_vm_t* stx = fsc->stx; | ||
|  | 
 | ||
|  | 	for (i = 0; i < fsc->literal_count; i++) { | ||
|  | 		c = STIX_ISSMALLINT(fsc->literals[i])?  | ||
|  | 			stx->class_smallinteger: STIX_CLASS (stx, fsc->literals[i]); | ||
|  | 		if (c != stx->class_string) continue; | ||
|  | 
 | ||
|  | 		if (stix_strxncmp (str, size,  | ||
|  | 			STIX_DATA(stx,fsc->literals[i]),  | ||
|  | 			STIX_SIZE(stx,fsc->literals[i])) == 0) return i; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	literal = stix_instantiate ( | ||
|  | 		stx, stx->class_string, STIX_NULL, str, size); | ||
|  | 	return __add_literal (fsc, literal); | ||
|  | } | ||
|  | 
 | ||
|  | static int __add_symbol_literal ( | ||
|  | 	stix_t* fsc, const stix_char_t* str, stix_word_t size) | ||
|  | { | ||
|  | 	stix_vm_t* stx = fsc->stx; | ||
|  | 	return __add_literal (fsc, stix_new_symbolx(stx, str, size)); | ||
|  | } | ||
|  | 
 | ||
|  | static int finish_method (stix_t* fsc) | ||
|  | { | ||
|  | 	stix_vm_t* stx = fsc->stx; | ||
|  | 	stix_class_t* class_obj; | ||
|  | 	stix_method_t* method_obj; | ||
|  | 	stix_word_t method, selector; | ||
|  | 
 | ||
|  | 	STIX_ASSERT (fsc->bcd.size != 0); | ||
|  | 
 | ||
|  | 	class_obj = (stix_class_t*) STIX_OBJPTR(stx, fsc->method_class); | ||
|  | 
 | ||
|  | 	if (class_obj->methods == stx->nil)  | ||
|  | 	{ | ||
|  | 		/* TODO: reconfigure method dictionary size */ | ||
|  | 		class_obj->methods = stix_instantiate ( | ||
|  | 			stx, stx->class_system_dictionary,  | ||
|  | 			STIX_NULL, STIX_NULL, 64); | ||
|  | 	} | ||
|  | 	STIX_ASSERT (class_obj->methods != stx->nil); | ||
|  | 
 | ||
|  | 	selector = stix_new_symbolx ( | ||
|  | 		stx, fsc->met.name.buf, fsc->method_name.size); | ||
|  | 
 | ||
|  | 	method = stix_instantiate(stx, stx->class_method,  | ||
|  | 		STIX_NULL, fsc->literals, fsc->literal_count); | ||
|  | 	method_obj = (stix_method_t*)STIX_OBJPTR(stx, method); | ||
|  | 
 | ||
|  | 	/* TODO: text saving must be optional */ | ||
|  | 	/*method_obj->text = stix_instantiate (
 | ||
|  | 		stx, stx->class_string, STIX_NULL,  | ||
|  | 		fsc->text, stix_strlen(fsc->text)); | ||
|  | 	*/ | ||
|  | 	method_obj->selector = selector; | ||
|  | 	method_obj->bytecodes = stix_instantiate ( | ||
|  | 		stx, stx->class_bytearray, STIX_NULL,  | ||
|  | 		fsc->bcd.buf, fsc->bcd.size); | ||
|  | 
 | ||
|  | 	/* TODO: better way to store argument count & temporary count */ | ||
|  | 	method_obj->tmpcount = STIX_TO_SMALLINT(fsc->met.tmpr.count - fsc->met.tmpr.nargs); | ||
|  | 	method_obj->argcount = STIX_TO_SMALLINT(fsc->met.tmpr.nargs); | ||
|  | 
 | ||
|  | 	stix_dict_put (stx, class_obj->methods, selector, method); | ||
|  | 	return 0; | ||
|  | } | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #if 0
 | ||
|  | 
 | ||
|  | static int parse_statements (stix_t* fsc) | ||
|  | { | ||
|  | 	/*
 | ||
|  | 	 * <statements> ::= (ORIGINAL->maybe wrong) | ||
|  | 	 * 	(<return statement> ['.'] ) | | ||
|  | 	 * 	(<expression> ['.' [<statements>]]) | ||
|  | 	 * <statements> ::= (REVISED->correct?) | ||
|  | 	 * 	<statement> ['. [<statements>]] | ||
|  | 	 */ | ||
|  | 
 | ||
|  | 	while (fsc->tok.type != STIX_FSC_TOK_EOF)  | ||
|  | 	{ | ||
|  | 		if (parse_statement (fsc) == -1) return -1; | ||
|  | 
 | ||
|  | 		if (fsc->tok.type == STIX_FSC_TOK_PERIOD)  | ||
|  | 		{ | ||
|  | 			GET_TOKEN (fsc); | ||
|  | 			continue; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (fsc->tok.type != STIX_FSC_TOK_EOF)  | ||
|  | 		{ | ||
|  | 			fsc->errnum = STIX_FSC_ERROR_NO_PERIOD; | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	EMIT_CODE (fsc, RETURN_RECEIVER); | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int parse_block_statements (stix_t* fsc) | ||
|  | { | ||
|  | 	while (fsc->tok.type != STIX_FSC_TOK_RBRACK &&  | ||
|  | 	       fsc->tok.type != STIX_FSC_TOK_EOF) { | ||
|  | 
 | ||
|  | 		if (parse_statement(fsc) == -1) return -1; | ||
|  | 		if (fsc->tok.type != STIX_FSC_TOK_PERIOD) break; | ||
|  | 		GET_TOKEN (fsc); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int parse_statement (stix_t* fsc) | ||
|  | { | ||
|  | 	/* 
 | ||
|  | 	 * <statement> ::= <return statement> | <expression> | ||
|  | 	 * <return statement> ::= returnOperator <expression>  | ||
|  | 	 * returnOperator ::= '^' | ||
|  | 	 */ | ||
|  | 
 | ||
|  | 	if (fsc->tok.type == STIX_FSC_TOK_RETURN) { | ||
|  | 		GET_TOKEN (fsc); | ||
|  | 		if (parse_expression(fsc) == -1) return -1; | ||
|  | 		EMIT_RETURN_FROM_MESSAGE (fsc); | ||
|  | 	} | ||
|  | 	else { | ||
|  | 		if (parse_expression(fsc) == -1) return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int parse_expression (stix_t* fsc) | ||
|  | { | ||
|  | 	/*
 | ||
|  | 	 * <expression> ::= <assignment> | <basic expression> | ||
|  | 	 * <assignment> ::= <assignment target> assignmentOperator <expression> | ||
|  | 	 * <basic expression> ::= <primary> [<messages> <cascaded messages>] | ||
|  | 	 * <assignment target> ::= identifier | ||
|  | 	 * assignmentOperator ::=  ':=' | ||
|  | 	 */ | ||
|  | 	stix_vm_t* stx = fsc->stx; | ||
|  | 
 | ||
|  | 	if (fsc->tok.type == STIX_FSC_TOK_IDENT) { | ||
|  | 		stix_char_t* ident = stix_tok_yield (&fsc->tok, 0); | ||
|  | 		if (ident == STIX_NULL) { | ||
|  | 			fsc->errnum = STIX_FSC_ERROR_MEMORY; | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		GET_TOKEN (fsc); | ||
|  | 		if (fsc->tok.type == STIX_FSC_TOK_ASSIGN) { | ||
|  | 			GET_TOKEN (fsc); | ||
|  | 			if (parse_assignment(fsc, ident) == -1) { | ||
|  | 				stix_free (ident); | ||
|  | 				return -1; | ||
|  | 			} | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			if (parse_basic_expression(fsc, ident) == -1) { | ||
|  | 				stix_free (ident); | ||
|  | 				return -1; | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		stix_free (ident); | ||
|  | 	} | ||
|  | 	else  | ||
|  | 	{ | ||
|  | 		if (parse_basic_expression(fsc, STIX_NULL) == -1) return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int parse_basic_expression ( | ||
|  | 	stix_t* fsc, const stix_char_t* ident) | ||
|  | { | ||
|  | 	/*
 | ||
|  | 	 * <basic expression> ::= <primary> [<messages> <cascaded messages>] | ||
|  | 	 */ | ||
|  | 	int is_super; | ||
|  | 
 | ||
|  | 	if (parse_primary(fsc, ident, &is_super) == -1) return -1; | ||
|  | 	if (fsc->tok.type != STIX_FSC_TOK_EOF && | ||
|  | 	    fsc->tok.type != STIX_FSC_TOK_PERIOD)  | ||
|  | 	{ | ||
|  | 		if (parse_message_continuation(fsc, is_super) == -1) return -1; | ||
|  | 	} | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int parse_assignment ( | ||
|  | 	stix_t* fsc, const stix_char_t* target) | ||
|  | { | ||
|  | 	/*
 | ||
|  | 	 * <assignment> ::= <assignment target> assignmentOperator <expression> | ||
|  | 	 */ | ||
|  | 
 | ||
|  | 	stix_word_t i; | ||
|  | 	stix_vm_t* stx = fsc->stx; | ||
|  | 
 | ||
|  | 	for (i = fsc->met.tmpr.nargs; i < fsc->met.tmpr.count; i++)  | ||
|  | 	{ | ||
|  | 		if (stix_strequal (target, fsc->met.tmpr.names[i]))  | ||
|  | 		{ | ||
|  | 			if (parse_expression(fsc) == -1) return -1; | ||
|  | 			EMIT_STORE_TEMPORARY_LOCATION (fsc, i); | ||
|  | 			return 0; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (stix_get_instance_variable_index (stx, fsc->method_class, target, &i) == 0)  | ||
|  | 	{ | ||
|  | 		if (parse_expression(fsc) == -1) return -1; | ||
|  | 		EMIT_STORE_RECEIVER_VARIABLE (fsc, i); | ||
|  | 		return 0; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (stix_lookup_class_variable (stx, fsc->method_class, target) != stx->nil)  | ||
|  | 	{ | ||
|  | 		if (parse_expression(fsc) == -1) return -1; | ||
|  | 
 | ||
|  | 		/* TODO */ | ||
|  | 		EMIT_CODE_TEST (fsc, STIX_T("ASSIGN_CLASSVAR #"), target); | ||
|  | 		//EMIT_STORE_CLASS_VARIABLE (fsc, target);
 | ||
|  | 		return 0; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/* TODO: IMPLEMENT POOL DICTIONARIES */ | ||
|  | 
 | ||
|  | 	/* TODO: IMPLEMENT GLOBLAS, but i don't like this idea */ | ||
|  | 
 | ||
|  | 	fsc->errnum = STIX_FSC_ERROR_UNDECLARED_NAME; | ||
|  | 	return -1; | ||
|  | } | ||
|  | 
 | ||
|  | static int parse_primary ( | ||
|  | 	stix_t* fsc, const stix_char_t* ident, int* is_super) | ||
|  | { | ||
|  | 	/*
 | ||
|  | 	 * <primary> ::= | ||
|  | 	 * 	identifier | <literal> |  | ||
|  | 	 * 	<block constructor> | ( '('<expression>')' ) | ||
|  | 	 */ | ||
|  | 
 | ||
|  | 	stix_vm_t* stx = fsc->stx; | ||
|  | 
 | ||
|  | 	if (ident == STIX_NULL)  | ||
|  | 	{ | ||
|  | 		int pos; | ||
|  | 		stix_word_t literal; | ||
|  | 
 | ||
|  | 		*is_super = stix_false; | ||
|  | 
 | ||
|  | 		if (fsc->tok.type == STIX_FSC_TOK_IDENT)  | ||
|  | 		{ | ||
|  | 			if (parse_primary_ident(fsc,  | ||
|  | 				fsc->tok.name.buffer, is_super) == -1) return -1; | ||
|  | 			GET_TOKEN (fsc); | ||
|  | 		} | ||
|  | 		else if (fsc->tok.type == STIX_FSC_TOK_CHRLIT) { | ||
|  | 			pos = __add_character_literal( | ||
|  | 				fsc, fsc->tok.name.buffer[0]); | ||
|  | 			if (pos == -1) return -1; | ||
|  | 			EMIT_PUSH_LITERAL_CONSTANT (fsc, pos); | ||
|  | 			GET_TOKEN (fsc); | ||
|  | 		} | ||
|  | 		else if (fsc->tok.type == STIX_FSC_TOK_STRLIT) { | ||
|  | 			pos = __add_string_literal (fsc, | ||
|  | 				fsc->tok.name.buffer, fsc->tok.name.size); | ||
|  | 			if (pos == -1) return -1; | ||
|  | 			EMIT_PUSH_LITERAL_CONSTANT (fsc, pos); | ||
|  | 			GET_TOKEN (fsc); | ||
|  | 		} | ||
|  | 		else if (fsc->tok.type == STIX_FSC_TOK_NUMLIT)  | ||
|  | 		{ | ||
|  | 			/* TODO: other types of numbers, negative numbers, etc */ | ||
|  | 			stix_word_t tmp; | ||
|  | 			STIX_STRTOI (tmp, fsc->tok.name.buffer, STIX_NULL, 10); | ||
|  | 			literal = STIX_TO_SMALLINT(tmp); | ||
|  | 			pos = __add_literal(fsc, literal); | ||
|  | 			if (pos == -1) return -1; | ||
|  | 			EMIT_PUSH_LITERAL_CONSTANT (fsc, pos); | ||
|  | 			GET_TOKEN (fsc); | ||
|  | 		} | ||
|  | 		else if (fsc->tok.type == STIX_FSC_TOK_SYMLIT) { | ||
|  | 			pos = __add_symbol_literal (fsc, | ||
|  | 				fsc->tok.name.buffer, fsc->tok.name.size); | ||
|  | 			if (pos == -1) return -1; | ||
|  | 			EMIT_PUSH_LITERAL_CONSTANT (fsc, pos); | ||
|  | 			GET_TOKEN (fsc); | ||
|  | 		} | ||
|  | 		else if (fsc->tok.type == STIX_FSC_TOK_LBRACK) { | ||
|  | 			GET_TOKEN (fsc); | ||
|  | 			if (parse_block_constructor(fsc) == -1) return -1; | ||
|  | 		} | ||
|  | 		else if (fsc->tok.type == STIX_FSC_TOK_APAREN) { | ||
|  | 			/* TODO: array literal */ | ||
|  | 		} | ||
|  | 		else if (fsc->tok.type == STIX_FSC_TOK_LPAREN) { | ||
|  | 			GET_TOKEN (fsc); | ||
|  | 			if (parse_expression(fsc) == -1) return -1; | ||
|  | 			if (fsc->tok.type != STIX_FSC_TOK_RPAREN) { | ||
|  | 				fsc->errnum = STIX_FSC_ERROR_NO_RPAREN; | ||
|  | 				return -1; | ||
|  | 			} | ||
|  | 			GET_TOKEN (fsc); | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			fsc->errnum = STIX_FSC_ERROR_PRIMARY; | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	else { | ||
|  | 		/*if (parse_primary_ident(fsc, fsc->tok.name.buffer) == -1) return -1;*/ | ||
|  | 		if (parse_primary_ident(fsc, ident, is_super) == -1) return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int parse_primary_ident ( | ||
|  | 	stix_t* fsc, const stix_char_t* ident, int* is_super) | ||
|  | { | ||
|  | 	stix_word_t i; | ||
|  | 	stix_vm_t* stx = fsc->stx; | ||
|  | 
 | ||
|  | 	*is_super = stix_false; | ||
|  | 
 | ||
|  | 	if (stix_strequal(ident, STIX_T("self")))  | ||
|  | 	{ | ||
|  | 		EMIT_CODE (fsc, PUSH_RECEIVER); | ||
|  | 		return 0; | ||
|  | 	} | ||
|  | 	else if (stix_strequal(ident, STIX_T("super")))  | ||
|  | 	{ | ||
|  | 		*is_super = stix_true; | ||
|  | 		EMIT_CODE (fsc, PUSH_RECEIVER); | ||
|  | 		return 0; | ||
|  | 	} | ||
|  | 	else if (stix_strequal(ident, STIX_T("nil")))  | ||
|  | 	{ | ||
|  | 		EMIT_CODE (fsc, PUSH_NIL); | ||
|  | 		return 0; | ||
|  | 	} | ||
|  | 	else if (stix_strequal(ident, STIX_T("true")))  | ||
|  | 	{ | ||
|  | 		EMIT_CODE (fsc, PUSH_TRUE); | ||
|  | 		return 0; | ||
|  | 	} | ||
|  | 	else if (stix_strequal(ident, STIX_T("false")))  | ||
|  | 	{ | ||
|  | 		EMIT_CODE (fsc, PUSH_FALSE); | ||
|  | 		return 0; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/* Refer to parse_assignment for identifier lookup */ | ||
|  | 
 | ||
|  | 	for (i = 0; i < fsc->met.tmpr.count; i++)  | ||
|  | 	{ | ||
|  | 		if (stix_strequal(ident, fsc->met.tmpr.names[i]))  | ||
|  | 		{ | ||
|  | 			EMIT_PUSH_TEMPORARY_LOCATION (fsc, i); | ||
|  | 			return 0; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (get_instance_variable_index ( | ||
|  | 		stx, fsc->method_class, ident, &i) == 0)  | ||
|  | 	{ | ||
|  | 		EMIT_PUSH_RECEIVER_VARIABLE (fsc, i); | ||
|  | 		return 0; | ||
|  | 	}	 | ||
|  | 
 | ||
|  | 	/* TODO: what is the best way to look up a class variable? */ | ||
|  | 	/* 1. Use the class containing it and using its position */ | ||
|  | 	/* 2. Use a primitive method after pushing the name as a symbol */ | ||
|  | 	/* 3. Implement a vm instruction to do it */ | ||
|  | /*
 | ||
|  | 	if (stix_lookup_class_variable ( | ||
|  | 		stx, fsc->method_class, ident) != stx->nil) { | ||
|  | 		//EMIT_LOOKUP_CLASS_VARIABLE (fsc, ident);
 | ||
|  | 		return 0; | ||
|  | 	} | ||
|  | */ | ||
|  | 
 | ||
|  | 	/* TODO: IMPLEMENT POOL DICTIONARIES */ | ||
|  | 
 | ||
|  | 	/* TODO: IMPLEMENT GLOBLAS, but i don't like this idea */ | ||
|  | 
 | ||
|  | 	fsc->errnum = STIX_FSC_ERROR_UNDECLARED_NAME; | ||
|  | 	return -1; | ||
|  | } | ||
|  | 
 | ||
|  | static int parse_block_constructor (stix_t* fsc) | ||
|  | { | ||
|  | 	/*
 | ||
|  | 	 * <block constructor> ::= '[' <block body> ']' | ||
|  | 	 * <block body> ::= [<block argument>* '|'] | ||
|  | 	 * 	[<temporaries>] [<statements>] | ||
|  | 	 * <block argument> ::= ':'  identifier | ||
|  | 	 */ | ||
|  | 
 | ||
|  | 	if (fsc->tok.type == STIX_FSC_TOK_COLON)  | ||
|  | 	{ | ||
|  | 		do  | ||
|  | 		{ | ||
|  | 			GET_TOKEN (fsc); | ||
|  | 
 | ||
|  | 			if (fsc->tok.type != STIX_FSC_TOK_IDENT)  | ||
|  | 			{ | ||
|  | 				fsc->errnum = STIX_FSC_ERROR_BLOCK_ARGUMENT_NAME; | ||
|  | 				return -1; | ||
|  | 			} | ||
|  | 
 | ||
|  | 			/* TODO : store block arguments */ | ||
|  | 			GET_TOKEN (fsc); | ||
|  | 		}  | ||
|  | 		while (fsc->tok.type == STIX_FSC_TOK_COLON); | ||
|  | 			 | ||
|  | 		if (!is_vbar_tok(&fsc->tok))  | ||
|  | 		{ | ||
|  | 			fsc->errnum = STIX_FSC_ERROR_BLOCK_ARGUMENT_LIST; | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		GET_TOKEN (fsc); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/* TODO: create a block closure */ | ||
|  | 	if (parse_method_temporaries(fsc) == -1) return -1; | ||
|  | 	if (parse_block_statements(fsc) == -1) return -1; | ||
|  | 
 | ||
|  | 	if (fsc->tok.type != STIX_FSC_TOK_RBRACK)  | ||
|  | 	{ | ||
|  | 		fsc->errnum = STIX_FSC_ERROR_BLOCK_NOT_CLOSED; | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	GET_TOKEN (fsc); | ||
|  | 
 | ||
|  | 	/* TODO: do special treatment for block closures */ | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int parse_message_continuation ( | ||
|  | 	stix_t* fsc, int is_super) | ||
|  | { | ||
|  | 	/*
 | ||
|  | 	 * <messages> ::= | ||
|  | 	 * 	(<unary message>+ <binary message>* [<keyword message>] ) | | ||
|  | 	 * 	(<binary message>+ [<keyword message>] ) | | ||
|  | 	 * 	<keyword message> | ||
|  | 	 * <cascaded messages> ::= (';' <messages>)* | ||
|  | 	 */ | ||
|  | 	if (parse_keyword_message(fsc, is_super) == -1) return -1; | ||
|  | 
 | ||
|  | 	while (fsc->tok.type == STIX_FSC_TOK_SEMICOLON)  | ||
|  | 	{ | ||
|  | 		EMIT_CODE_TEST (fsc, STIX_T("DoSpecial(DUP_RECEIVER(CASCADE))"), STIX_T("")); | ||
|  | 		GET_TOKEN (fsc); | ||
|  | 
 | ||
|  | 		if (parse_keyword_message(fsc, stix_false) == -1) return -1; | ||
|  | 		EMIT_CODE_TEST (fsc, STIX_T("DoSpecial(POP_TOP)"), STIX_T("")); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int parse_keyword_message (stix_t* fsc, int is_super) | ||
|  | { | ||
|  | 	/*
 | ||
|  | 	 * <keyword message> ::= (keyword <keyword argument> )+ | ||
|  | 	 * <keyword argument> ::= <primary> <unary message>* <binary message>* | ||
|  | 	 */ | ||
|  | 
 | ||
|  | 	stix_name_t name; | ||
|  | 	stix_word_t pos; | ||
|  | 	int is_super2; | ||
|  | 	int nargs = 0, n; | ||
|  | 
 | ||
|  | 	if (parse_binary_message (fsc, is_super) == -1) return -1; | ||
|  | 	if (fsc->tok.type != STIX_FSC_TOK_KEYWORD) return 0; | ||
|  | 
 | ||
|  | 	if (stix_name_open(&name, 0) == STIX_NULL) { | ||
|  | 		fsc->errnum = STIX_FSC_ERROR_MEMORY; | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 	 | ||
|  | 	do  | ||
|  | 	{ | ||
|  | 		if (stix_name_adds(&name, fsc->tok.name.buffer) == -1)  | ||
|  | 		{ | ||
|  | 			fsc->errnum = STIX_FSC_ERROR_MEMORY; | ||
|  | 			stix_name_close (&name); | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		GET_TOKEN (fsc); | ||
|  | 		if (parse_primary(fsc, STIX_NULL, &is_super2) == -1)  | ||
|  | 		{ | ||
|  | 			stix_name_close (&name); | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (parse_binary_message(fsc, is_super2) == -1)  | ||
|  | 		{ | ||
|  | 			stix_name_close (&name); | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		nargs++; | ||
|  | 		/* TODO: check if it has too many arguments.. */ | ||
|  | 	}  | ||
|  | 	while (fsc->tok.type == STIX_FSC_TOK_KEYWORD); | ||
|  | 
 | ||
|  | 	pos = __add_symbol_literal (fsc, name.buffer, name.size); | ||
|  | 	if (pos == -1)  | ||
|  | 	{ | ||
|  | 		stix_name_close (&name); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	n = (is_super)? emit_send_to_super(fsc,nargs,pos): | ||
|  | 	                emit_send_to_self(fsc,nargs,pos); | ||
|  | 	if (n == -1) { | ||
|  | 		stix_name_close (&name); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	stix_name_close (&name); | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int parse_binary_message (stix_t* fsc, int is_super) | ||
|  | { | ||
|  | 	/*
 | ||
|  | 	 * <binary message> ::= binarySelector <binary argument> | ||
|  | 	 * <binary argument> ::= <primary> <unary message>* | ||
|  | 	 */ | ||
|  | 	stix_word_t pos; | ||
|  | 	int is_super2; | ||
|  | 	int n; | ||
|  | 
 | ||
|  | 	if (parse_unary_message (fsc, is_super) == -1) return -1; | ||
|  | 
 | ||
|  | 	while (fsc->tok.type == STIX_FSC_TOK_BINSEL)  | ||
|  | 	{ | ||
|  | 		stix_char_t* op = stix_tok_yield (&fsc->tok, 0); | ||
|  | 		if (op == STIX_NULL) { | ||
|  | 			fsc->errnum = STIX_FSC_ERROR_MEMORY; | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		GET_TOKEN (fsc); | ||
|  | 		if (parse_primary(fsc, STIX_NULL, &is_super2) == -1) { | ||
|  | 			stix_free (op); | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (parse_unary_message(fsc, is_super2) == -1) { | ||
|  | 			stix_free (op); | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		pos = __add_symbol_literal (fsc, op, stix_strlen(op)); | ||
|  | 		if (pos == -1) { | ||
|  | 			stix_free (op); | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		n = (is_super)? | ||
|  | 			emit_send_to_super(fsc,2,pos): | ||
|  | 			emit_send_to_self(fsc,2,pos); | ||
|  | 		if (n == -1) { | ||
|  | 			stix_free (op); | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		stix_free (op); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int parse_unary_message (stix_t* fsc, int is_super) | ||
|  | { | ||
|  | 	/* <unary message> ::= unarySelector */ | ||
|  | 
 | ||
|  | 	stix_word_t pos; | ||
|  | 	int n; | ||
|  | 
 | ||
|  | 	while (fsc->tok.type == STIX_FSC_TOK_IDENT)  | ||
|  | 	{ | ||
|  | 		pos = __add_symbol_literal (fsc, | ||
|  | 			fsc->tok.name.buffer, fsc->tok.name.size); | ||
|  | 		if (pos == -1) return -1; | ||
|  | 
 | ||
|  | 		n = (is_super)? emit_send_to_super (fsc, 0, pos): | ||
|  | 		                emit_send_to_self (fsc, 0, pos); | ||
|  | 		if (n == -1) return -1; | ||
|  | 
 | ||
|  | 		GET_TOKEN (fsc); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int parse_method (stix_t* fsc, stix_word_t method_class, void* input) | ||
|  | { | ||
|  | 	/*
 | ||
|  | 	 * <method definition> ::=  | ||
|  | 	 * 	<message pattern> [<temporaries>] [<primitive>] [<statements>] | ||
|  | 	 */ | ||
|  | 
 | ||
|  | 	GET_CHAR (fsc); | ||
|  | 	GET_TOKEN (fsc); | ||
|  | 
 | ||
|  | 	stix_name_clear (&fsc->method_name); | ||
|  | 	stix_arr_clear (&fsc->bcd); | ||
|  | 
 | ||
|  | 	while (fsc->met.tmpr.count > 0)  | ||
|  | 	{ | ||
|  | 		stix_free (fsc->met.tmpr.names[--fsc->met.tmpr.count]); | ||
|  | 	} | ||
|  | 	fsc->met.tmpr.nargs = 0; | ||
|  | 	fsc->literal_count = 0; | ||
|  | 
 | ||
|  | 	if (parse_method_name_pattern(fsc) <= -1 || | ||
|  | 	    parse_method_temporaries(fsc) <= -1 || | ||
|  | 	    parse_method_primitive(fsc) <= -1 || | ||
|  | 	    parse_statements(fsc) <= -1 || | ||
|  | 	    finish_method (fsc) <= -1) return -1; | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | static int get_class_type (const stix_char_t* str, class_type_t* type) | ||
|  | { | ||
|  | 	static struct  | ||
|  | 	{ | ||
|  | 		stix_char_t* word; | ||
|  | 		class_type_t type; | ||
|  | 	} tab[] =  | ||
|  | 	{ | ||
|  | 		{ STIX_T("class"),             CLASS_NORMAL }, | ||
|  | 		{ STIX_T("variableClass"),     CLASS_VARIABLE }, | ||
|  | 		{ STIX_T("variableByteClass"), CLASS_VARIABLE_BYTE }, | ||
|  | 		{ STIX_T("variableCharClass"), CLASS_VARIABLE_CHAR } | ||
|  | 	}; | ||
|  | 
 | ||
|  | 	int i; | ||
|  | 
 | ||
|  | 	for (i = 0; i < STIX_COUNTOF(tab); i++) | ||
|  | 	{ | ||
|  | 		if (stix_strequal(str, tab[i].word))  | ||
|  | 		{ | ||
|  | 			*type = tab[i].type; | ||
|  | 			return 0; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return -1; | ||
|  | } | ||
|  | 
 | ||
|  | static int get_vardef_type (const stix_char_t* str, vardef_type_t* type) | ||
|  | { | ||
|  | 	static struct  | ||
|  | 	{ | ||
|  | 		stix_char_t* word; | ||
|  | 		class_type_t type; | ||
|  | 	} tab[] =  | ||
|  | 	{ | ||
|  | 		{ STIX_T("|-"), VARDEF_INSTANCE }, | ||
|  | 		{ STIX_T("|+"), VARDEF_CLASS_INSTANCE }, | ||
|  | 		{ STIX_T("|*"), VARDEF_CLASS } | ||
|  | 		/* TODO: shared pools */ | ||
|  | 	}; | ||
|  | 
 | ||
|  | 	int i; | ||
|  | 
 | ||
|  | 	for (i = 0; i < STIX_COUNTOF(tab); i++) | ||
|  | 	{ | ||
|  | 		if (stix_strequal(str, tab[i].word))  | ||
|  | 		{ | ||
|  | 			*type = tab[i].type; | ||
|  | 			return 0; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return -1; | ||
|  | } | ||
|  | 
 | ||
|  | static int compile_vardef (stix_t* fsc, vardef_type_t vardef_type) | ||
|  | { | ||
|  | 	return -1; | ||
|  | } | ||
|  | 
 | ||
|  | static int parse_unary_pattern (stix_t* fsc) | ||
|  | { | ||
|  | 	STIX_ASSERT (fsc->met.name.len == 0); | ||
|  | 	STIX_ASSERT (fsc->met.tmpr.nargs == 0); | ||
|  | 
 | ||
|  | /* TODO: check if the method name exists */ | ||
|  | 
 | ||
|  | 	if (fsc->tok.name.len >= STIX_COUNTOF(fsc->met.name.buf)) | ||
|  | 	{ | ||
|  | 		stix_seterror (fsc, STIX_FSC_EMETNTL, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/* collect the method name */ | ||
|  | 	fsc->met.name.len = stix_strcpy (fsc->met.name.buf, fsc->tok.name.ptr); | ||
|  | 	GET_TOKEN (fsc); | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int parse_binary_pattern (stix_t* fsc) | ||
|  | { | ||
|  | 	STIX_ASSERT (fsc->met.name.len == 0); | ||
|  | 	STIX_ASSERT (fsc->met.tmpr.nargs == 0); | ||
|  | 
 | ||
|  | /* TODO: check if the method name exists */ | ||
|  | 	if (fsc->tok.name.len >= STIX_COUNTOF(fsc->met.name.buf)) | ||
|  | 	{ | ||
|  | 		stix_seterror (fsc, STIX_FSC_EMETNTL, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/* collect the method name */ | ||
|  | 	fsc->met.name.len = stix_strcpy (fsc->met.name.buf, fsc->tok.name.ptr); | ||
|  | 	GET_TOKEN (fsc); | ||
|  | 
 | ||
|  | 	/* collect the argument name */ | ||
|  | 	if (fsc->tok.type != STIX_FSC_TOK_IDENT)  | ||
|  | 	{ | ||
|  | 		stix_seterror (fsc, STIX_FSC_EILARGN, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	STIX_ASSERT (fsc->met.tmpr.nargs == 0); | ||
|  | 	/*
 | ||
|  | 	 * check if there are too many arguments defined. | ||
|  | 	 * however, in this function, this condition will never be met. | ||
|  | 	 * so let me just comment out the check. | ||
|  | 	 * | ||
|  | 	if (fsc->met.tmpr.nargs >= STIX_COUNTOF(fsc->met.tmpr.names))  | ||
|  | 	{ | ||
|  | 		stix_seterror (fsc, STIX_FSC_ETMARGS, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 	*/ | ||
|  | 
 | ||
|  | /* TODO: check for duplicate entries...in instvars */ | ||
|  | 
 | ||
|  | 	if (fsc->tok.name.len >= STIX_COUNTOF(fsc->met.tmpr.names[fsc->met.tmpr.count])) | ||
|  | 	{ | ||
|  | 		/* argument name is too long */ | ||
|  | 		stix_seterror (fsc, STIX_FSC_EARGNTL, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 	stix_strcpy (fsc->met.tmpr.names[fsc->met.tmpr.nargs], fsc->tok.name.ptr); | ||
|  | 	fsc->met.tmpr.nargs++; | ||
|  | 
 | ||
|  | 	GET_TOKEN (fsc); | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int parse_keyword_pattern (stix_t* fsc) | ||
|  | { | ||
|  | 	STIX_ASSERT (fsc->met.name.len == 0); | ||
|  | 	STIX_ASSERT (fsc->met.tmpr.nargs == 0); | ||
|  | 
 | ||
|  | 	do  | ||
|  | 	{ | ||
|  | 		if (fsc->tok.name.len + fsc->met.name.len >= STIX_COUNTOF(fsc->met.name.buf)) | ||
|  | 		{ | ||
|  | 			stix_seterror (fsc, STIX_FSC_EMETNTL, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 		fsc->met.name.len += stix_strcpy (&fsc->met.name.buf[fsc->met.name.len], fsc->tok.name.ptr); | ||
|  | 
 | ||
|  | 		GET_TOKEN (fsc); | ||
|  | 		if (fsc->tok.type != STIX_FSC_TOK_IDENT || is_tok_pseudovar(fsc))  | ||
|  | 		{ | ||
|  | 			stix_seterror (fsc, STIX_FSC_EILARGN, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (fsc->met.tmpr.nargs >= STIX_COUNTOF(fsc->met.tmpr.names))  | ||
|  | 		{ | ||
|  | 			/* too many arguments */ | ||
|  | 			stix_seterror (fsc, STIX_FSC_ETMARGS, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 
 | ||
|  | /* TODO: check for duplicate entries...in instvars/arguments */ | ||
|  | 		if (fsc->tok.name.len >= STIX_COUNTOF(fsc->met.tmpr.names[fsc->met.tmpr.nargs])) | ||
|  | 		{ | ||
|  | 			/* argument name is too long */ | ||
|  | 			stix_seterror (fsc, STIX_FSC_EARGNTL, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 		stix_strcpy (fsc->met.tmpr.names[fsc->met.tmpr.nargs], fsc->tok.name.ptr); | ||
|  | 		fsc->met.tmpr.nargs++; | ||
|  | 
 | ||
|  | 		GET_TOKEN (fsc); | ||
|  | 	}  | ||
|  | 	while (fsc->tok.type == STIX_FSC_TOK_KEYWORD); | ||
|  | 
 | ||
|  | 	/* TODO: check if the method name exists */ | ||
|  | 	/* if it exists, collapse arguments */ | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int parse_method_name_pattern (stix_t* fsc) | ||
|  | { | ||
|  | 	/* 
 | ||
|  | 	 * <message pattern> ::= <unary pattern> | <binary pattern> | <keyword pattern> | ||
|  | 	 * <unary pattern> ::= unarySelector | ||
|  | 	 * <binary pattern> ::= binarySelector <method argument> | ||
|  | 	 * <keyword pattern> ::= (keyword  <method argument>)+ | ||
|  | 	 */ | ||
|  | 	int n; | ||
|  | 
 | ||
|  | 	STIX_ASSERT (fsc->met.tmpr.count == 0); | ||
|  | 
 | ||
|  | 	switch (fsc->tok.type) | ||
|  | 	{ | ||
|  | 		case STIX_FSC_TOK_IDENT: | ||
|  | 			n = parse_unary_pattern (fsc); | ||
|  | 			break; | ||
|  | 
 | ||
|  | 		case STIX_FSC_TOK_BINSEL: | ||
|  | 			n = parse_binary_pattern (fsc); | ||
|  | 			break; | ||
|  | 
 | ||
|  | 		case STIX_FSC_TOK_KEYWORD: | ||
|  | 			n = parse_keyword_pattern (fsc); | ||
|  | 			break; | ||
|  | 
 | ||
|  | 		default: | ||
|  | 			stix_seterror (fsc, STIX_FSC_EILMETN, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 			n = -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/* the total number of temporaries is equal to the number of arguments
 | ||
|  | 	 * after having processed the message pattern */ | ||
|  | 	fsc->met.tmpr.count = fsc->met.tmpr.nargs; | ||
|  | 	return n; | ||
|  | } | ||
|  | 
 | ||
|  | static int parse_method_temporaries (stix_t* fsc) | ||
|  | { | ||
|  | 	/* 
 | ||
|  | 	 * <temporaries> ::= '|' <temporary variable list> '|' | ||
|  | 	 * <temporary variable list> ::= identifier* | ||
|  | 	 */ | ||
|  | 
 | ||
|  | 	if (!is_tok_binsel (fsc, STIX_T("|"))) return 0; | ||
|  | 
 | ||
|  | 	GET_TOKEN (fsc); | ||
|  | 	while (fsc->tok.type == STIX_FSC_TOK_IDENT)  | ||
|  | 	{ | ||
|  | 		if (fsc->met.tmpr.count >= STIX_COUNTOF(fsc->met.tmpr.names))  | ||
|  | 		{ | ||
|  | 			stix_seterror (fsc, STIX_FSC_ETMTMPS, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (is_tok_pseudovar(fsc))  | ||
|  | 		{ | ||
|  | 			stix_seterror (fsc, STIX_FSC_EILTMPN, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 
 | ||
|  | /* TODO: check for duplicate entries...in instvars/arguments/temporaries */ | ||
|  | 
 | ||
|  | 		if (fsc->tok.name.len >= STIX_COUNTOF(fsc->met.tmpr.names[fsc->met.tmpr.count])) | ||
|  | 		{ | ||
|  | 			/* temporary variable name is too long */ | ||
|  | 			stix_seterror (fsc, STIX_FSC_ETMPNTL, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 		stix_strcpy (fsc->met.tmpr.names[fsc->met.tmpr.count], fsc->tok.name.ptr); | ||
|  | 		fsc->met.tmpr.count++; | ||
|  | 
 | ||
|  | 		GET_TOKEN (fsc); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (!is_tok_binsel (fsc, STIX_T("|"))) return 0; | ||
|  | 	{ | ||
|  | 		stix_seterror (fsc, STIX_FSC_EVRTBAR, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	GET_TOKEN (fsc); | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int parse_method_primitive (stix_t* fsc) | ||
|  | { | ||
|  | 	/* 
 | ||
|  | 	 * <primitive> ::= '<' 'primitive:' number '>' | ||
|  | 	 */ | ||
|  | 
 | ||
|  | 	int prim_no; | ||
|  | 
 | ||
|  | 	if (!is_tok_binsel (fsc, STIX_T("<"))) return 0; | ||
|  | 
 | ||
|  | 	GET_TOKEN (fsc); | ||
|  | 	if (fsc->tok.type != STIX_FSC_TOK_KEYWORD || | ||
|  | 	    !stix_strequal (fsc->tok.name.ptr, STIX_T("primitive:")))  | ||
|  | 	{ | ||
|  | 		fsc->errnum = STIX_FSC_ERROR_PRIMITIVE_KEYWORD; | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	GET_TOKEN (fsc); /* TODO: only integer */ | ||
|  | 	if (fsc->tok.type != STIX_FSC_TOK_NUMLIT)  | ||
|  | 	{ | ||
|  | 		fsc->errnum = STIX_FSC_ERROR_PRIMITIVE_NUMBER; | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | /*TODO: more checks the validity of the primitive number */ | ||
|  | 	if (!stix_stristype(fsc->tok.name.buffer, stix_isdigit))  | ||
|  | 	{ | ||
|  | 		fsc->errnum = STIX_FSC_ERROR_PRIMITIVE_NUMBER; | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	STIX_STRTOI (prim_no, fsc->tok.name.buffer, STIX_NULL, 10); | ||
|  | 	if (prim_no < 0 || prim_no > 0xFF)  | ||
|  | 	{ | ||
|  | 		fsc->errnum = STIX_FSC_ERROR_PRIMITIVE_NUMBER_RANGE; | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	EMIT_DO_PRIMITIVE (fsc, prim_no); | ||
|  | 
 | ||
|  | 	GET_TOKEN (fsc); | ||
|  | 	if (!is_tok_binsel (fsc, STIX_T(">"))) return 0; | ||
|  | 	{ | ||
|  | 		stix_seterror (fsc, STIX_FSC_ERABRCK, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	GET_TOKEN (fsc); | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | static int compile_method (stix_t* fsc, int instance) | ||
|  | { | ||
|  | 	/* clear data required to compile a method */ | ||
|  | 	STIX_MEMSET (&fsc->met, 0, STIX_SIZEOF(fsc->met)); | ||
|  | 
 | ||
|  | #if 0
 | ||
|  | 	/* clear the byte-code buffer */ | ||
|  | 	fsc->bcd.len = 0; | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 	if (parse_method_name_pattern (fsc) <= -1) return -1; | ||
|  | 
 | ||
|  | 	if (fsc->tok.type != STIX_FSC_TOK_LBRACE) | ||
|  | 	{ | ||
|  | 		/* { expected */ | ||
|  | 		stix_seterror (fsc, STIX_FSC_ELBRACE, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 	GET_TOKEN (fsc); | ||
|  | 
 | ||
|  | 	if (parse_method_temporaries (fsc) <= -1 || | ||
|  | 	    parse_method_primitive (fsc) <= -1 /*||
 | ||
|  | 	    parse_statements (fsc) <= -1 || | ||
|  | 	    finish_method (fsc) <= -1*/) return -1;  | ||
|  | 
 | ||
|  | 	if (fsc->tok.type != STIX_FSC_TOK_RBRACE) | ||
|  | 	{ | ||
|  | 		/* } expected */ | ||
|  | 		stix_seterror (fsc, STIX_FSC_ERBRACE, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 	GET_TOKEN (fsc); | ||
|  | 
 | ||
|  | wprintf (L"METHOD NAME ==> [%S] temporaries => %d\n", fsc->met.name.buf, fsc->met.tmpr.count); | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int compile_classdef (stix_t* fsc, class_type_t class_type) | ||
|  | { | ||
|  | 	stix_oop_t oop1, oop2; | ||
|  | 	int extend; | ||
|  | 
 | ||
|  | 	if (fsc->tok.type != STIX_FSC_TOK_IDENT) | ||
|  | 	{ | ||
|  | 		/* class name expected. */ | ||
|  | 		stix_seterror (fsc, STIX_FSC_ECLSNAM, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (stix_vm_findclass (fsc->vm, fsc->tok.name.ptr, &oop1) <= -1) | ||
|  | 	{ | ||
|  | 		/* this class is a new class. you can only extend an existing class */ | ||
|  | 		GET_TOKEN (fsc); | ||
|  | 		if (fsc->tok.type == STIX_FSC_TOK_IDENT &&  | ||
|  | 		    stix_strequal (fsc->tok.name.ptr, STIX_T("extend"))) | ||
|  | 		{ | ||
|  | 			GET_TOKEN (fsc); | ||
|  | 			if (fsc->tok.type != STIX_FSC_TOK_IDENT) | ||
|  | 			{ | ||
|  | 				stix_seterror (fsc, STIX_FSC_ECLSNAM, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 				return -1; | ||
|  | 			} | ||
|  | 
 | ||
|  | 			if (stix_vm_findclass (fsc->vm, fsc->tok.name.ptr, &oop2) <= -1) | ||
|  | 			{ | ||
|  | 				stix_seterror (fsc, STIX_FSC_EILBCLS, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 				return -1; | ||
|  | 			} | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			stix_seterror (fsc, STIX_FSC_EEXTEND, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		extend = 1; | ||
|  | 	} | ||
|  | 	else | ||
|  | 	{ | ||
|  | /* TODO: check the existing class layout againt class_type (variableByteClass, variableCharClass, class, etc).
 | ||
|  |  * if no match, return -1 */ | ||
|  | 		extend = 0; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	GET_TOKEN (fsc); | ||
|  | 	if (fsc->tok.type != STIX_FSC_TOK_LBRACE) | ||
|  | 	{ | ||
|  | 		/* { expected */ | ||
|  | 		stix_seterror (fsc, STIX_FSC_ELBRACE, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	GET_TOKEN (fsc); | ||
|  | 
 | ||
|  | 	if (!extend) | ||
|  | 	{ | ||
|  | 		while (1) | ||
|  | 		{ | ||
|  | 			vardef_type_t vardef_type; | ||
|  | 
 | ||
|  | 			/* TODO: compile other components including various pragma statements 
 | ||
|  | 			 * <category: ...> | ||
|  | 			 * <comment: ...> | ||
|  | 			 */ | ||
|  | 			if (fsc->tok.type == STIX_FSC_TOK_BINSEL && | ||
|  | 			    get_vardef_type (fsc->tok.name.ptr, &vardef_type) >= 0) | ||
|  | 			{ | ||
|  | 				if (compile_vardef (fsc, vardef_type) <= -1) return -1; | ||
|  | 			} | ||
|  | 			else | ||
|  | 			{ | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	while (1) | ||
|  | 	{ | ||
|  | 		/* TODO: compile other components including various pragma statements 
 | ||
|  | 		 * <category: ...> | ||
|  | 		 * <comment: ...> | ||
|  | 		 */ | ||
|  | 		if (is_tok_binsel (fsc, STIX_T("-")))  | ||
|  | 		{ | ||
|  | 			GET_TOKEN (fsc); | ||
|  | 			if (compile_method (fsc, 1) <= -1) return -1; | ||
|  | 		} | ||
|  | 		else if (is_tok_binsel (fsc, STIX_T("+"))) | ||
|  | 		{ | ||
|  | 			GET_TOKEN (fsc); | ||
|  | 			if (compile_method (fsc, 0) <= -1) return -1; | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			break; | ||
|  | 		}	 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (fsc->tok.type != STIX_FSC_TOK_RBRACE) | ||
|  | 	{ | ||
|  | 		/* TODO: } expected */ | ||
|  | 		stix_seterror (fsc, STIX_FSC_ERBRACE, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	GET_TOKEN (fsc); | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | static int compile_directive (stix_t* fsc) | ||
|  | { | ||
|  | 	if (fsc->tok.type == STIX_FSC_TOK_IDENT) | ||
|  | 	{ | ||
|  | 		class_type_t class_type; | ||
|  | 
 | ||
|  | 		if (get_class_type (fsc->tok.name.ptr, &class_type) >= 0) | ||
|  | 		{ | ||
|  | 			if (get_token (fsc) <= -1) return -1; | ||
|  | 			return compile_classdef (fsc, class_type); | ||
|  | 		} | ||
|  | 		else if (stix_strequal (fsc->tok.name.ptr, STIX_T("include"))) | ||
|  | 		{ | ||
|  | 			if (get_token (fsc) <= -1) return -1; | ||
|  | 
 | ||
|  | 			if (fsc->tok.type != STIX_FSC_TOK_STRLIT) | ||
|  | 			{ | ||
|  | 				stix_seterror (fsc, STIX_FSC_ESTRLIT, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 				return -1; | ||
|  | 			} | ||
|  | 
 | ||
|  | 			if (begin_include (fsc) <= -1) return -1; | ||
|  | 		} | ||
|  | 		else | ||
|  | 		{ | ||
|  | 			stix_seterror (fsc, STIX_FSC_EILDIR, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	else | ||
|  | 	{ | ||
|  | 		stix_seterror (fsc, STIX_FSC_EILDIR, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int compile_stream (stix_t* fsc) | ||
|  | { | ||
|  | 	GET_CHAR (fsc); | ||
|  | 	GET_TOKEN (fsc); | ||
|  | 
 | ||
|  | 	while (fsc->tok.type != STIX_FSC_TOK_EOF) | ||
|  | 	{ | ||
|  | 		if (is_tok_binsel (fsc, STIX_T("@"))) | ||
|  | 		{ | ||
|  | 			GET_TOKEN (fsc); | ||
|  | 			if (compile_directive (fsc) <= -1) return -1; | ||
|  | 		} | ||
|  | 		/* TODO: normal smalltalk message sending expressions */ | ||
|  | 		else  | ||
|  | 		{ | ||
|  | 			stix_seterror (fsc, STIX_FSC_EILTTOK, &fsc->tok.name, &fsc->tok.loc); | ||
|  | 			return -1; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | } | ||
|  | #endif
 | ||
|  | 
 | ||
|  | int stix_compile (stix_t* stix, stix_ioimpl_t io) | ||
|  | { | ||
|  | 	int n; | ||
|  | 
 | ||
|  | 	if (!io) | ||
|  | 	{ | ||
|  | 		stix->errnum = STIX_EINVAL; | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	STIX_ASSERT (stix->c == STIX_NULL); | ||
|  | 
 | ||
|  | 	stix->c = stix_callocmem (stix, STIX_SIZEOF(*stix->c)); | ||
|  | 	if (!stix->c) return -1; | ||
|  | 	stix->c->impl = io; | ||
|  | 	stix->c->arg.line = 1; | ||
|  | 	stix->c->arg.colm = 1; | ||
|  | 	stix->c->curinp = &stix->c->arg; | ||
|  | 	clear_sio_names (stix); | ||
|  | 
 | ||
|  | 	/* open the top-level stream */ | ||
|  | 	n = stix->c->impl (stix, STIX_IO_OPEN, stix->c->curinp); | ||
|  | 	if (n <= -1) return -1; | ||
|  | 
 | ||
|  | 	if (compile_stream (stix) <= -1) goto oops; | ||
|  | 
 | ||
|  | 	/* close the stream */ | ||
|  | 	STIX_ASSERT (stix->c->curinp == &stix->c->arg); | ||
|  | 	stix->c->impl (stix, STIX_IO_CLOSE, stix->c->curinp); | ||
|  | 	 | ||
|  | 	stix_freemem (stix, stix->c); | ||
|  | 	stix->c = STIX_NULL; | ||
|  | 	return 0; | ||
|  | 
 | ||
|  | oops: | ||
|  | 	/* an error occurred and control has reached here
 | ||
|  | 	 * probably, some included files might not have been  | ||
|  | 	 * closed. close them */ | ||
|  | 	while (stix->c->curinp != &stix->c->arg) | ||
|  | 	{ | ||
|  | 		stix_ioarg_t* prev; | ||
|  | 
 | ||
|  | 		/* nothing much to do about a close error */ | ||
|  | 		stix->c->impl (stix, STIX_IO_CLOSE, stix->c->curinp); | ||
|  | 
 | ||
|  | 		prev = stix->c->curinp->includer; | ||
|  | 		STIX_ASSERT (stix->c->curinp->name != STIX_NULL); | ||
|  | 		STIX_MMGR_FREE (stix->mmgr, stix->c->curinp); | ||
|  | 		stix->c->curinp = prev; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	stix->c->impl (stix, STIX_IO_CLOSE, stix->c->curinp); | ||
|  | 
 | ||
|  | 	stix_freemem (stix, stix->c); | ||
|  | 	stix->c = STIX_NULL; | ||
|  | 	return -1; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 |