/* PCE.c Primary Composition Engine */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_MALLOC_H #include #endif #ifdef HAVE_STDLIB_H #include #endif /******************************************************************************** Declarations *********************************************************************************/ #define PCE_MAX_NUMBER ((1 << 23) - 1) #define PCE_DICTIONARY_DEFAULT_SIZE 17 #define PCE_CALL_MAX_DEPTH 16 typedef struct PCE_code PCE_code; typedef struct PCE_data PCE_data; typedef struct PCE_context PCE_context; typedef struct PCE_funcproto PCE_funcproto; typedef struct PCE_function PCE_function; typedef struct PCE_inst_template PCE_inst_template; typedef struct PCE_parse_context PCE_parse_context; typedef struct PCE_label PCE_label; typedef struct PCE_labelset PCE_labelset; typedef EIMIL_value* (*PCE_EXEC_HANDLER)(PCE_context *pctx); struct PCE_data { PCE_code *pcode; }; typedef enum PCE_ERROR_CODE (*PCE_SEH_TRY_FUNCTION)(PCE_context *pctx, void *arg); typedef enum PCE_ERROR_CODE (*PCE_SEH_CATCH_FUNCTION)(PCE_context *pctx, int ecode, void *throwarg, void *catcharg); typedef struct PCE_SEH_catchblock PCE_SEH_catchblock; typedef struct PCE_SEH_block PCE_SEH_block; struct PCE_SEH_catchblock { int type; PCE_SEH_CATCH_FUNCTION pcfs; void *catcharg; PCE_SEH_catchblock *pnext; }; struct PCE_SEH_block { jmp_buf jmp; void *arg; PCE_SEH_catchblock *pcatchers; PCE_SEH_block *pnext; }; struct PCE_context { int depth; PCE_code *pcur; EIMIL_data *ped; EIMIL_dictionary *pdic; EIMIL_dictionary *pdic_f; EIMIL_symbol *psym_cev; PCE_data *ppce_data; EIMIL_dictionary *pfuncdic[PCE_CALL_MAX_DEPTH]; PCE_SEH_block *pseh; }; struct PCE_funcproto { EIMIL_symbol *psym; enum EIMIL_TYPE type; }; struct PCE_function { int nargs; PCE_funcproto *pfp; EIMIL_dictionary *pdic; int rettype; PCE_code *pc; }; enum PCE_CODE_TYPE { PCE_CODE_INST, PCE_CODE_VALUE, PCE_CODE_MAIN, PCE_CODE_DEFUN, PCE_CODE_JMP, PCE_CODE_UNRESOLVED_JMP, PCE_CODE_COND_JMP, PCE_CODE_UNRESOLVED_COND_JMP, PCE_CODE_COND_NOT_JMP, PCE_CODE_UNRESOLVED_COND_NOT_JMP, PCE_CODE_SYMBOL = (1 << 16), PCE_CODE_FUNCTION }; #define PCE_ARG_MAX 5 struct PCE_inst_template { enum PCE_CODE_TYPE code_type; PCE_EXEC_HANDLER handler; enum EIMIL_TYPE result; int newmode; int required_type[PCE_ARG_MAX]; }; #define PCE_SET_REQUIRED_TYPES(PCX, PIT) \ (memcpy((PCX)->required_type, (PIT)->required_type, sizeof((PCX)->required_type))) struct PCE_label { int id; PCE_code *pc; EIMIL_symbol *psym; /* If this flag is set, the label will be set to the next code. */ int nextp; }; struct PCE_labelset { int labelnum; int allocednum; EIMIL_dictionary *pdic; PCE_label *pl; }; struct PCE_parse_context { PCE_context *pctx; int idx; unsigned int mode; int required_type[PCE_ARG_MAX]; enum EIMIL_TYPE result; EIMIL_dictionary *pdic; EIMIL_symbol *psym; PCE_function *pf; PCE_code *pc; PCE_code *pc_head; PCE_labelset *plabels; int labelid; int labelid2; PCE_parse_context *pnext; }; struct PCE_code { enum PCE_CODE_TYPE type; union { PCE_EXEC_HANDLER h; EIMIL_value *pv; EIMIL_SYMID symid; PCE_function *pf; PCE_code *pc_to; int to_labelid; } val; void *poption; PCE_code *parg; PCE_code *pnext; }; enum PCE_CONTEXT_MODE { PCE_IN_MAIN = (1 << 0), PCE_IN_TRY = (1 << 1), PCE_IN_CATCH = (1 << 2), PCE_IN_DEFVAR = (1 << 3), PCE_DEFVAR_NIL = (1 << 4), PCE_DEFVAR_DONE = (1 << 5), PCE_IN_DEFUN = (1 << 6), PCE_IN_DEFTABLE = (1 << 7), PCE_IN_DEFPATTERN = (1 << 8), PCE_CONTEXT_MODE_PERSISTENT_MASK = (1 << 16) - 1, PCE_IN_IF = (1 << 16), PCE_IN_ELSE = (1 << 17), PCE_IN_E = (1 << 18), PCE_IN_SELECT = (1 << 19), PCE_SELECT_HAS_DEFAULT = (1 << 20), PCE_ONLY_IN_MAIN_STATEMENT = (1 << 21) }; #define PCE_NEW_PARSER_CONTEXT_MODE(pcx, m) \ (((pcx)->mode & PCE_CONTEXT_MODE_PERSISTENT_MASK) | (m)) #define PCE_SET_PARSER_CONTEXT_MODE(pcx, m) \ ((pcx)->mode | (m)) #define PCE_RESET_PARSER_CONTEXT_MODE(pcx, m) \ ((pcx)->mode & (~(m))) #define PCE_ADD_CODE(PCX, PCODE) \ (((PCODE)->pnext = (PCX)->pc), ((PCX)->pc = (PCODE)), ((PCX)->idx++)) /******************************************************************************** PCE error handling. *********************************************************************************/ enum PCE_ERROR_CODE { PCE_ANY_ERROR = -1, PCE_SUCCESS = 0, PCE_UNKNOWN_ERROR, PCE_MEMORY_ERROR, PCE_LITERAL_OVERFLOW, PCE_DEC_NUMBER_ERROR, PCE_HEX_NUMBER_ERROR, PCE_CHAR_LITERAL_ERROR, PCE_MTEXT_LITERAL_ERROR, PCE_NOT_VARIABLE_ERROR, PCE_NOT_FUNCTION_ERROR, PCE_NOT_EXCEPTION_ERROR, PCE_LABEL_NOT_DEFINED_ERROR, PCE_PARSE_NOT_LITERAL, PCE_PARSE_SYNTAX_ERROR, PCE_PARSE_UNKNOWN_SYMBOL_ERROR, PCE_PARSE_INVALID_SYMBOL_ERROR, PCE_PARSE_RETURN_IN_DEFUN_ERROR, PCE_TOO_FEW_ARGUMENTS_ERROR, PCE_WRONG_TYPE_ARGUMENT_ERROR, PCE_VARIABLE_CONSTANT_ERROR, PCE_OUT_OF_RANGE_ERROR, PCE_OVER_EVAL_DEPTH_ERROR, PCE_DEFVAR_DONE_ERROR, PCE_DEFVAR_NIL_ERROR, PCE_RETURN_JMP_ERROR, PCE_WAIT_NEXT_EVENT_ERROR, PCE_NO_MORE_ARG_ERROR }; static void PCE_set_error( EIMIL_data *ped, enum PCE_ERROR_CODE code ) { switch (code) { case PCE_LITERAL_OVERFLOW: EIMIL_set_error_pt(ped, NULL, "Overflow in the literal."); return; case PCE_DEC_NUMBER_ERROR: EIMIL_set_error_pt(ped, NULL, "Syntax error in the decimal number."); break; case PCE_HEX_NUMBER_ERROR: EIMIL_set_error_pt(ped, NULL, "Syntax error in the hexadecimal number."); break; case PCE_CHAR_LITERAL_ERROR: EIMIL_set_error_pt(ped, NULL, "Syntax error in the char literal."); break; case PCE_MTEXT_LITERAL_ERROR: EIMIL_set_error_pt(ped, NULL, "Syntax error in the mtext literal."); break; case PCE_TOO_FEW_ARGUMENTS_ERROR: EIMIL_set_error_pt(ped, NULL, "Too few arguments."); return; case PCE_DEFVAR_DONE_ERROR: EIMIL_set_error_pt(ped, NULL, "Initiali value must be only one in defvar."); return; case PCE_DEFVAR_NIL_ERROR: EIMIL_set_error_pt(ped, NULL, "The variable in defvar must be initialized to nil."); return; case PCE_PARSE_UNKNOWN_SYMBOL_ERROR: EIMIL_set_error_pt(ped, NULL, "Unknown symbol."); return; case PCE_PARSE_RETURN_IN_DEFUN_ERROR: EIMIL_set_error_pt(ped, NULL, "`return' must be in `defun'."); return; case PCE_NOT_VARIABLE_ERROR: EIMIL_set_error_pt(ped, NULL, "It is not a variable."); return; case PCE_NOT_FUNCTION_ERROR: EIMIL_set_error_pt(ped, NULL, "It is not a function."); return; case PCE_NOT_EXCEPTION_ERROR: EIMIL_set_error_pt(ped, NULL, "It is not an exception."); return; default: EIMIL_set_error_pt(ped, NULL, "PCE internal error (parser)."); } return; } /******************************************************************************** PCE document template *********************************************************************************/ static const UTF8* PCE_classname = "com.sun.iiim.pce1.s1"; static const UTF8* PCE_xmlns_uri = "http://www.OpenI18N.org/EIMIL/NS/PCE/1.0"; #define DECLARE_PARSER_METHOD(name) \ static int PCE_##name##_parser( \ EIMIL_data *ped, \ EIMIL_attrs *patr, \ enum EIMIL_TAG_TYPE type, \ UTF8 *pchars, \ void **pprivate \ ) #define DEFINE_PARSER_METHOD(name) DECLARE_PARSER_METHOD(name) static int PCE_generic_inst_parser( EIMIL_data *ped, EIMIL_attrs *patr, enum EIMIL_TAG_TYPE type, UTF8 *pchars, void **pprivate ); /* instrunction element template. */ #define PCE_noarg_option (EIMIL_element_EMPTY | EIMIL_element_multiple) #define PCE_arg_option (EIMIL_element_multiple | EIMIL_allow_PCDATA | EIMIL_PCDATA_QUOTED_TOKEN) #define DEFINE_SINST_TEMPLATE_1(name, kind, type, mode, arg1) \ static PCE_inst_template \ PCE_##name##_inst_template = {kind, NULL, type, mode, {arg1}} #define DEFINE_SINST_TEMPLATE_0(name, kind, type, mode) \ DEFINE_SINST_TEMPLATE_1(name, kind, type, mode, 0) #define DEFINE_INST_TEMPLATE_5(name, type, mode, arg1, arg2, arg3, arg4, arg5) \ static PCE_inst_template \ PCE_##name##_inst_template = {PCE_CODE_INST, PCE_##name##_exec, type, mode, \ {arg1, arg2, arg3, arg4, arg5}} #define DEFINE_INST_TEMPLATE_4(name, type, mode, arg1, arg2, arg3, arg4) \ DEFINE_INST_TEMPLATE_5(name, type, mode, arg1, arg2, arg3, arg4, 0) #define DEFINE_INST_TEMPLATE_3(name, type, mode, arg1, arg2, arg3) \ DEFINE_INST_TEMPLATE_5(name, type, mode, arg1, arg2, arg3, 0, 0) #define DEFINE_INST_TEMPLATE_2(name, type, mode, arg1, arg2) \ DEFINE_INST_TEMPLATE_5(name, type, mode, arg1, arg2, 0, 0, 0) #define DEFINE_INST_TEMPLATE_1(name, type, mode, arg1) \ DEFINE_INST_TEMPLATE_5(name, type, mode, arg1, 0, 0, 0, 0) #define DEFINE_INST_TEMPLATE_0(name, type, mode) \ DEFINE_INST_TEMPLATE_5(name, type, mode, 0, 0, 0, 0, 0) #define INST_ELEMENT_TEMPLATE(name, strname) \ {(strname), PCE_generic_inst_parser, NULL, \ PCE_arg_option, PCE_statement_template, \ &PCE_##name##_inst_template} #define INST_ELEMENT_TEMPLATE_NOARG(name, strname) \ {(strname), PCE_generic_inst_parser, NULL, \ PCE_noarg_option, NULL, \ &PCE_##name##_inst_template} #define INST_ELEMENT_TEMPLATE_OPTION(name, strname, option) \ {(strname), PCE_generic_inst_parser, NULL, \ (option), PCE_statement_template, \ &PCE_##name##_inst_template} #define DECLARE_EXEC_METHOD(name) \ static EIMIL_value* PCE_##name##_exec( \ PCE_context *pctx \ ) #define DEFINE_EXEC_METHOD(name) DECLARE_EXEC_METHOD(name) DECLARE_PARSER_METHOD(PCE); DECLARE_PARSER_METHOD(mnemonic); DECLARE_PARSER_METHOD(pattern); DECLARE_PARSER_METHOD(key); DECLARE_PARSER_METHOD(defvar); DECLARE_PARSER_METHOD(defun); DEFINE_SINST_TEMPLATE_1(defun, PCE_CODE_DEFUN, EIMIL_TYPE_NONE, 0, EIMIL_TYPE_ANY | EIMIL_TYPE_OPTION1); DECLARE_PARSER_METHOD(deftable); DECLARE_PARSER_METHOD(defkeymap); DECLARE_PARSER_METHOD(defpattern); DECLARE_PARSER_METHOD(main); DEFINE_SINST_TEMPLATE_1(main, PCE_CODE_MAIN, EIMIL_TYPE_NONE, 0, EIMIL_TYPE_ANY | EIMIL_TYPE_OPTION1); DECLARE_PARSER_METHOD(while); DECLARE_PARSER_METHOD(go); DECLARE_PARSER_METHOD(label); DECLARE_PARSER_METHOD(undo); DECLARE_EXEC_METHOD(undo); DEFINE_INST_TEMPLATE_0(undo, EIMIL_TYPE_NONE, 0); DECLARE_PARSER_METHOD(mark_undo); DECLARE_EXEC_METHOD(mark_undo); DEFINE_INST_TEMPLATE_0(mark_undo, EIMIL_TYPE_NONE, 0); DECLARE_PARSER_METHOD(try); DECLARE_EXEC_METHOD(try); DEFINE_INST_TEMPLATE_1(try, EIMIL_TYPE_NONE, 0, EIMIL_TYPE_ANY | EIMIL_TYPE_OPTION1); DECLARE_PARSER_METHOD(catch); DECLARE_EXEC_METHOD(catch); DEFINE_INST_TEMPLATE_1(catch, EIMIL_TYPE_NONE, 0, EIMIL_TYPE_ANY | EIMIL_TYPE_OPTION1); DECLARE_PARSER_METHOD(throw); DECLARE_EXEC_METHOD(throw); DEFINE_INST_TEMPLATE_0(throw, EIMIL_TYPE_NONE, 0); DECLARE_PARSER_METHOD(if); DECLARE_PARSER_METHOD(else); DECLARE_PARSER_METHOD(keycase); DECLARE_EXEC_METHOD(keycase); DEFINE_INST_TEMPLATE_1(keycase, EIMIL_TYPE_NONE, 0, EIMIL_TYPE_ANY | EIMIL_TYPE_OPTION1); DECLARE_PARSER_METHOD(keymap); DECLARE_EXEC_METHOD(keymap); DEFINE_INST_TEMPLATE_1(keymap, EIMIL_TYPE_NONE, 0, EIMIL_TYPE_ANY | EIMIL_TYPE_OPTION1); DECLARE_PARSER_METHOD(case); DECLARE_PARSER_METHOD(default); DECLARE_PARSER_METHOD(select); DECLARE_EXEC_METHOD(toggle_preedit); DEFINE_INST_TEMPLATE_1(toggle_preedit, EIMIL_TYPE_BOOL, 0, EIMIL_TYPE_BOOL); DECLARE_EXEC_METHOD(toggle_lookup_choice); DEFINE_INST_TEMPLATE_1(toggle_lookup_choice, EIMIL_TYPE_BOOL, 0, EIMIL_TYPE_BOOL); DECLARE_EXEC_METHOD(keyeventp); DEFINE_INST_TEMPLATE_1(keyeventp, EIMIL_TYPE_BOOL, 0, EIMIL_TYPE_EVENT); DECLARE_EXEC_METHOD(or); DEFINE_INST_TEMPLATE_1(or, EIMIL_TYPE_BOOL, 0, EIMIL_TYPE_ANY | EIMIL_TYPE_OPTION1); DECLARE_EXEC_METHOD(and); DEFINE_INST_TEMPLATE_1(and, EIMIL_TYPE_BOOL, 0, EIMIL_TYPE_ANY | EIMIL_TYPE_OPTION1); DECLARE_EXEC_METHOD(not); DEFINE_INST_TEMPLATE_1(not, EIMIL_TYPE_BOOL, 0, EIMIL_TYPE_ANY); DECLARE_EXEC_METHOD(gt); DEFINE_INST_TEMPLATE_2(gt, EIMIL_TYPE_BOOL, 0, EIMIL_TYPE_NUMBER, EIMIL_TYPE_NUMBER); DECLARE_EXEC_METHOD(lt); DEFINE_INST_TEMPLATE_2(lt, EIMIL_TYPE_BOOL, 0, EIMIL_TYPE_NUMBER, EIMIL_TYPE_NUMBER); DECLARE_EXEC_METHOD(le); DEFINE_INST_TEMPLATE_2(le, EIMIL_TYPE_BOOL, 0, EIMIL_TYPE_NUMBER, EIMIL_TYPE_NUMBER); DECLARE_EXEC_METHOD(ge); DEFINE_INST_TEMPLATE_2(ge, EIMIL_TYPE_BOOL, 0, EIMIL_TYPE_NUMBER, EIMIL_TYPE_NUMBER); DECLARE_EXEC_METHOD(eql); DEFINE_INST_TEMPLATE_2(eql, EIMIL_TYPE_BOOL, 0, EIMIL_TYPE_NUMBER, EIMIL_TYPE_NUMBER); DECLARE_EXEC_METHOD(propval); DEFINE_INST_TEMPLATE_2(propval, EIMIL_TYPE_ANY, 0, EIMIL_TYPE_PROP, EIMIL_TYPE_NUMBER); DECLARE_EXEC_METHOD(propsize); DEFINE_INST_TEMPLATE_1(propsize, EIMIL_TYPE_NUMBER, 0, EIMIL_TYPE_PROP); DECLARE_EXEC_METHOD(propmbeg); DEFINE_INST_TEMPLATE_1(propmbeg, EIMIL_TYPE_NUMBER, 0, EIMIL_TYPE_PROP); DECLARE_EXEC_METHOD(propmend); DEFINE_INST_TEMPLATE_1(propmend, EIMIL_TYPE_NUMBER, 0, EIMIL_TYPE_PROP); DECLARE_EXEC_METHOD(evval); DEFINE_INST_TEMPLATE_1(evval, EIMIL_TYPE_NUMBER, 0, EIMIL_TYPE_EVENT); DECLARE_EXEC_METHOD(evmod); DEFINE_INST_TEMPLATE_1(evmod, EIMIL_TYPE_NUMBER, 0, EIMIL_TYPE_EVENT); DECLARE_EXEC_METHOD(strlen); DEFINE_INST_TEMPLATE_1(strlen, EIMIL_TYPE_NUMBER, 0, EIMIL_TYPE_MTEXT); DECLARE_EXEC_METHOD(strcmp); DEFINE_INST_TEMPLATE_2(strcmp, EIMIL_TYPE_NUMBER, 0, EIMIL_TYPE_MTEXT, EIMIL_TYPE_MTEXT); DECLARE_EXEC_METHOD(add); DEFINE_INST_TEMPLATE_1(add, EIMIL_TYPE_NUMBER, 0, EIMIL_TYPE_NUMBER | EIMIL_TYPE_OPTION1); DECLARE_EXEC_METHOD(sub); DEFINE_INST_TEMPLATE_1(sub, EIMIL_TYPE_NUMBER, 0, EIMIL_TYPE_NUMBER | EIMIL_TYPE_OPTION1); DECLARE_EXEC_METHOD(mul); DEFINE_INST_TEMPLATE_1(mul, EIMIL_TYPE_NUMBER, 0, EIMIL_TYPE_NUMBER | EIMIL_TYPE_OPTION1); DECLARE_EXEC_METHOD(div); DEFINE_INST_TEMPLATE_1(div, EIMIL_TYPE_NUMBER, 0, EIMIL_TYPE_NUMBER | EIMIL_TYPE_OPTION1); DECLARE_EXEC_METHOD(mod); DEFINE_INST_TEMPLATE_1(mod, EIMIL_TYPE_NUMBER, 0, EIMIL_TYPE_NUMBER | EIMIL_TYPE_OPTION1); DECLARE_EXEC_METHOD(bor); DEFINE_INST_TEMPLATE_1(bor, EIMIL_TYPE_NUMBER, 0, EIMIL_TYPE_NUMBER | EIMIL_TYPE_OPTION1); DECLARE_EXEC_METHOD(band); DEFINE_INST_TEMPLATE_1(band, EIMIL_TYPE_NUMBER, 0, EIMIL_TYPE_NUMBER | EIMIL_TYPE_OPTION1); DECLARE_EXEC_METHOD(bxor); DEFINE_INST_TEMPLATE_1(bxor, EIMIL_TYPE_NUMBER, 0, EIMIL_TYPE_NUMBER | EIMIL_TYPE_OPTION1); DECLARE_EXEC_METHOD(UCSval); DEFINE_INST_TEMPLATE_1(UCSval, EIMIL_TYPE_NUMBER, 0, EIMIL_TYPE_CHAR); DECLARE_EXEC_METHOD(propadd); DEFINE_INST_TEMPLATE_2(propadd, EIMIL_TYPE_PROP, 0, EIMIL_TYPE_PROP, EIMIL_TYPE_ANY); DECLARE_EXEC_METHOD(propcopy); DEFINE_INST_TEMPLATE_1(propcopy, EIMIL_TYPE_PROP, 0, EIMIL_TYPE_PROP); DECLARE_EXEC_METHOD(evchar); DEFINE_INST_TEMPLATE_1(evchar, EIMIL_TYPE_CHAR, 0, EIMIL_TYPE_EVENT); DECLARE_EXEC_METHOD(strref); DEFINE_INST_TEMPLATE_2(strref, EIMIL_TYPE_CHAR, 0, EIMIL_TYPE_MTEXT, EIMIL_TYPE_NUMBER); DECLARE_EXEC_METHOD(makechar); DEFINE_INST_TEMPLATE_1(makechar, EIMIL_TYPE_CHAR, 0, EIMIL_TYPE_NUMBER); DECLARE_EXEC_METHOD(evtype); DEFINE_INST_TEMPLATE_1(evtype, EIMIL_TYPE_MTEXT, 0, EIMIL_TYPE_EVENT); DECLARE_EXEC_METHOD(evmtext); DEFINE_INST_TEMPLATE_1(evmtext, EIMIL_TYPE_MTEXT, 0, EIMIL_TYPE_EVENT); DECLARE_EXEC_METHOD(concat); DEFINE_INST_TEMPLATE_1(concat, EIMIL_TYPE_MTEXT, 0, EIMIL_TYPE_CHAR | EIMIL_TYPE_MTEXT | EIMIL_TYPE_OPTION1); DECLARE_EXEC_METHOD(substr); DEFINE_INST_TEMPLATE_3(substr, EIMIL_TYPE_MTEXT, 0, EIMIL_TYPE_MTEXT, EIMIL_TYPE_NUMBER, EIMIL_TYPE_NUMBER | EIMIL_TYPE_OPTION2); DECLARE_EXEC_METHOD(next); DEFINE_INST_TEMPLATE_2(next, EIMIL_TYPE_NONE, PCE_ONLY_IN_MAIN_STATEMENT, EIMIL_TYPE_EVENT, EIMIL_TYPE_EVENT | EIMIL_TYPE_OPTION2); DECLARE_EXEC_METHOD(makeev); DEFINE_INST_TEMPLATE_5(makeev, EIMIL_TYPE_EVENT, 0, EIMIL_TYPE_MTEXT, EIMIL_TYPE_NUMBER | EIMIL_TYPE_NIL, EIMIL_TYPE_NUMBER | EIMIL_TYPE_NIL, EIMIL_TYPE_CHAR | EIMIL_TYPE_NIL, EIMIL_TYPE_MTEXT | EIMIL_TYPE_NIL); DECLARE_EXEC_METHOD(commit); DEFINE_INST_TEMPLATE_1(commit, EIMIL_TYPE_NONE, 0, EIMIL_TYPE_MTEXT); DECLARE_EXEC_METHOD(unroll); DEFINE_INST_TEMPLATE_1(unroll, EIMIL_TYPE_NONE, 0, EIMIL_TYPE_EVENT); DECLARE_EXEC_METHOD(propdel); DEFINE_INST_TEMPLATE_2(propdel, EIMIL_TYPE_NONE, 0, EIMIL_TYPE_PROP, EIMIL_TYPE_NUMBER); DECLARE_EXEC_METHOD(addmprop); DEFINE_INST_TEMPLATE_4(addmprop, EIMIL_TYPE_NONE, 0, EIMIL_TYPE_MTEXT, EIMIL_TYPE_PROP, EIMIL_TYPE_NUMBER, EIMIL_TYPE_NUMBER); DECLARE_EXEC_METHOD(delmprop); DEFINE_INST_TEMPLATE_1(delmprop, EIMIL_TYPE_NONE, 0, EIMIL_TYPE_PROP); DECLARE_EXEC_METHOD(setmprop); DEFINE_INST_TEMPLATE_4(setmprop, EIMIL_TYPE_NONE, 0, EIMIL_TYPE_MTEXT, EIMIL_TYPE_PROP, EIMIL_TYPE_NUMBER, EIMIL_TYPE_NUMBER); DECLARE_PARSER_METHOD(return); DECLARE_EXEC_METHOD(return); DEFINE_INST_TEMPLATE_1(return, EIMIL_TYPE_NONE, 0, EIMIL_TYPE_ANY); DECLARE_PARSER_METHOD(tblkeymaxsize); DECLARE_EXEC_METHOD(tblkeymaxsize); DECLARE_PARSER_METHOD(tblvalmaxsize); DECLARE_EXEC_METHOD(tblvalmaxsize); DECLARE_PARSER_METHOD(tblref); DECLARE_EXEC_METHOD(tblref); DECLARE_PARSER_METHOD(makeprop); DECLARE_EXEC_METHOD(makeprop); DECLARE_PARSER_METHOD(getmprop); DECLARE_EXEC_METHOD(getmprop); DECLARE_PARSER_METHOD(findmprop); DECLARE_EXEC_METHOD(findmprop); DECLARE_PARSER_METHOD(interact); DECLARE_EXEC_METHOD(interact); DECLARE_PARSER_METHOD(match); DECLARE_EXEC_METHOD(match); DECLARE_PARSER_METHOD(forward); DECLARE_EXEC_METHOD(forward); DECLARE_PARSER_METHOD(send); DECLARE_EXEC_METHOD(send); DECLARE_PARSER_METHOD(set); DECLARE_EXEC_METHOD(set); DECLARE_PARSER_METHOD(e); DECLARE_EXEC_METHOD(e); #define EIMIL_TEMPLATE_NUM(e) (sizeof(e) / sizeof(EIMIL_element_template)) static EIMIL_element_template PCE_statement_template[]; /* */ static EIMIL_element_template PCE_if_else_template[] = { {"else", PCE_else_parser, NULL, EIMIL_element_0or1 | EIMIL_element_lock_template | EIMIL_allow_PCDATA | EIMIL_PCDATA_QUOTED_TOKEN, PCE_statement_template, NULL}, {NULL, NULL, NULL, 0, NULL, NULL} }; static EIMIL_element_template PCE_if_full_template[]; static EIMIL_attr_template PCE_attr_keycase[] = {{"code", EIMIL_attr_IMPLIED, NULL}, {"char", EIMIL_attr_IMPLIED, NULL}, {"mod", EIMIL_attr_IMPLIED, ""}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_keymap[] = {{"k", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; /* */ static EIMIL_element_template PCE_select_template[] = { {"case", PCE_case_parser, NULL, PCE_arg_option, PCE_statement_template, NULL}, {"default", PCE_default_parser, NULL, EIMIL_element_0or1 | EIMIL_element_lock_template | EIMIL_allow_PCDATA | EIMIL_PCDATA_QUOTED_TOKEN, PCE_statement_template, NULL}, {NULL, NULL, NULL, 0, NULL} }; /* */ static EIMIL_element_template PCE_try_catch_template[] = { INST_ELEMENT_TEMPLATE_OPTION(catch, "catch", PCE_arg_option | EIMIL_element_lock_template), {NULL, NULL, NULL, 0, NULL} }; static EIMIL_element_template PCE_try_full_template[]; static EIMIL_attr_template PCE_attr_go[] = {{"to", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_label[] = {{"name", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_catch[] = {{"exc", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_throw[] = {{"exc", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_interact[] = {{"op", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_next[] = {{"remove", EIMIL_attr_NORMAL, "true"}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_forward[] = {{"to", EIMIL_attr_IMPLIED, NULL}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_send[] = {{"to", EIMIL_attr_IMPLIED, NULL}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_e[] = {{"f", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_set[] = {{"v", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_match[] = {{"p", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_tblref[] = {{"t", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_tblkeymaxsize[] = {{"t", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_tblvalmaxsize[] = {{"t", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_makeprop[] = {{"p", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_propval[] = {{"p", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_getmprop[] = {{"p", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_findmprop[] = {{"p", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; static EIMIL_element_template PCE_statement_template[] = { /* Flow control */ {"while", PCE_while_parser, NULL, PCE_arg_option, PCE_statement_template, NULL}, /* undo */ INST_ELEMENT_TEMPLATE_NOARG(undo, "undo"), INST_ELEMENT_TEMPLATE_NOARG(mark_undo, "mark-undo"), /* STH */ {"try", PCE_try_parser, NULL, PCE_arg_option, PCE_try_full_template, &PCE_try_inst_template}, /* flow */ {"if", PCE_if_parser, NULL, PCE_arg_option, PCE_if_full_template, NULL}, {"select", PCE_select_parser, NULL, EIMIL_element_multiple, PCE_select_template, NULL}, /* BOOL */ INST_ELEMENT_TEMPLATE(toggle_preedit, "toggle-preedit"), INST_ELEMENT_TEMPLATE(toggle_lookup_choice, "toggle-lookup-choice"), INST_ELEMENT_TEMPLATE(keyeventp, "keyeventp"), INST_ELEMENT_TEMPLATE(or, "or"), INST_ELEMENT_TEMPLATE(and, "and"), INST_ELEMENT_TEMPLATE(not, "not"), INST_ELEMENT_TEMPLATE(gt, "gt"), INST_ELEMENT_TEMPLATE(lt, "lt"), INST_ELEMENT_TEMPLATE(le, "le"), INST_ELEMENT_TEMPLATE(ge, "ge"), INST_ELEMENT_TEMPLATE(eql, "eql"), INST_ELEMENT_TEMPLATE(propsize, "propsize"), INST_ELEMENT_TEMPLATE(propmbeg, "propmbeg"), INST_ELEMENT_TEMPLATE(propmend, "propmend"), INST_ELEMENT_TEMPLATE(evval, "evval"), INST_ELEMENT_TEMPLATE(evmod, "evmod"), INST_ELEMENT_TEMPLATE(strlen, "strlen"), INST_ELEMENT_TEMPLATE(strcmp, "strcmp"), INST_ELEMENT_TEMPLATE(add, "add"), INST_ELEMENT_TEMPLATE(sub, "sub"), INST_ELEMENT_TEMPLATE(mul, "mul"), INST_ELEMENT_TEMPLATE(div, "div"), INST_ELEMENT_TEMPLATE(mod, "mod"), INST_ELEMENT_TEMPLATE(bor, "bor"), INST_ELEMENT_TEMPLATE(band, "band"), INST_ELEMENT_TEMPLATE(bxor, "bxor"), INST_ELEMENT_TEMPLATE(UCSval, "UCSval"), INST_ELEMENT_TEMPLATE(propadd, "propadd"), INST_ELEMENT_TEMPLATE(propcopy, "propcopy"), INST_ELEMENT_TEMPLATE(evchar, "evchar"), INST_ELEMENT_TEMPLATE(makechar, "makechar"), INST_ELEMENT_TEMPLATE(strref, "strref"), INST_ELEMENT_TEMPLATE(commit, "commit"), INST_ELEMENT_TEMPLATE(next, "next"), INST_ELEMENT_TEMPLATE(evtype, "evtype"), INST_ELEMENT_TEMPLATE(evmtext, "evmtext"), INST_ELEMENT_TEMPLATE(commit, "commit"), INST_ELEMENT_TEMPLATE(concat, "concat"), INST_ELEMENT_TEMPLATE(substr, "substr"), INST_ELEMENT_TEMPLATE(makeev, "makeev"), INST_ELEMENT_TEMPLATE(unroll, "unroll"), INST_ELEMENT_TEMPLATE(propdel, "propdel"), INST_ELEMENT_TEMPLATE(addmprop, "addmprop"), INST_ELEMENT_TEMPLATE(addmprop, "delmprop"), INST_ELEMENT_TEMPLATE(addmprop, "setmprop"), /* PROP IDX retrives a value of property. */ INST_ELEMENT_TEMPLATE(propval, "propval"), /* returns a value of function. */ {"return", PCE_return_parser, NULL, PCE_arg_option, NULL, &PCE_return_inst_template}, /* exc(exception name) attribute */ {"throw", PCE_throw_parser, NULL, PCE_noarg_option, NULL, &PCE_throw_inst_template}, /* to(label name) attribute */ {"go", PCE_go_parser, PCE_attr_go, PCE_noarg_option, NULL, NULL}, /* name(label name) attribute */ {"label", PCE_label_parser, PCE_attr_label, PCE_noarg_option, NULL, NULL}, /* t(table name) attribute */ {"tblkeymaxsize", PCE_tblkeymaxsize_parser, NULL, EIMIL_element_EMPTY | EIMIL_element_multiple, NULL}, {"tblvalmaxsize", PCE_tblvalmaxsize_parser, NULL, EIMIL_element_EMPTY | EIMIL_element_multiple, NULL}, {"tblref", PCE_tblref_parser, NULL, PCE_arg_option, PCE_statement_template}, /* p(property name) attribute */ {"makeprop", PCE_makeprop_parser, NULL, EIMIL_element_EMPTY| EIMIL_element_multiple, NULL}, {"getmprop", PCE_getmprop_parser, NULL, PCE_arg_option, PCE_statement_template}, {"findmprop", PCE_findmprop_parser, NULL, PCE_arg_option, PCE_statement_template}, /* op(operation name) attribute */ {"interact", PCE_interact_parser, NULL, PCE_noarg_option, NULL}, /* p(pattern name) attribute */ {"match", PCE_match_parser, NULL, PCE_arg_option, PCE_statement_template}, /* to(EIMIL name) attribute */ {"forward", PCE_forward_parser, PCE_attr_forward, PCE_noarg_option, NULL}, {"send", PCE_send_parser, PCE_attr_send, PCE_arg_option, PCE_statement_template}, /* v(variable name) attribute */ {"set", PCE_set_parser, NULL, PCE_arg_option, PCE_statement_template}, /* f(function name) attribute */ {"e", PCE_e_parser, NULL, PCE_arg_option, PCE_statement_template}, /* ends here */ {NULL, NULL, NULL, 0, NULL} }; static EIMIL_element_template PCE_if_full_template[EIMIL_TEMPLATE_NUM(PCE_statement_template) + EIMIL_TEMPLATE_NUM(PCE_if_else_template) - 1]; static EIMIL_element_template PCE_try_full_template[EIMIL_TEMPLATE_NUM(PCE_statement_template) + EIMIL_TEMPLATE_NUM(PCE_try_catch_template) - 1]; static EIMIL_attr_template PCE_attr_defvar[] = {{"name", EIMIL_attr_REQUIRED, NULL}, {"type", EIMIL_attr_REQUIRED, NULL}, {"val", EIMIL_attr_NORMAL, "nil"}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_defun[] = {{"name", EIMIL_attr_REQUIRED, NULL}, {"type", EIMIL_attr_REQUIRED, NULL}, {"args", EIMIL_attr_NORMAL, ""}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_defpattern[] = {{"name", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_mnemonic[] = {{"c", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_pattern[] = {{"e", EIMIL_attr_REQUIRED, NULL}, {"v", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; static EIMIL_element_template PCE_defpattern_template[] = { {"mnemonic", PCE_mnemonic_parser, NULL, PCE_arg_option, NULL}, {"pattern", PCE_pattern_parser, PCE_attr_pattern, PCE_noarg_option, NULL}, {NULL, NULL, NULL, 0, NULL} }; static EIMIL_attr_template PCE_attr_deftable[] = {{"name", EIMIL_attr_REQUIRED, NULL}, {"from", EIMIL_attr_REQUIRED, NULL}, {"to", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; static EIMIL_attr_template PCE_attr_key[] = {{"code", EIMIL_attr_IMPLIED, NULL}, {"char", EIMIL_attr_IMPLIED, NULL}, {"mod", EIMIL_attr_IMPLIED, NULL}, {NULL, 0, NULL}}; static EIMIL_element_template PCE_defkeymap_template[] = { {"key", PCE_key_parser, NULL, PCE_arg_option, NULL}, {NULL, NULL, NULL, 0, NULL} }; static EIMIL_attr_template PCE_attr_defkeymap[] = {{"name", EIMIL_attr_REQUIRED, NULL}, {"to", EIMIL_attr_REQUIRED, NULL}, {NULL, 0, NULL}}; static EIMIL_element_template PCE_template[] = {{"defvar", PCE_defvar_parser, PCE_attr_defvar, PCE_arg_option, NULL}, {"defun", PCE_defun_parser, PCE_attr_defun, PCE_arg_option, PCE_statement_template, &PCE_defun_inst_template}, {"deftable", PCE_deftable_parser, PCE_attr_deftable, PCE_arg_option, NULL}, {"defkeymap", PCE_defkeymap_parser, PCE_attr_defkeymap, PCE_arg_option, PCE_defkeymap_template}, {"defpattern", PCE_defpattern_parser, PCE_attr_defpattern, PCE_arg_option, PCE_defpattern_template}, {"main", PCE_main_parser, NULL, EIMIL_element_single | EIMIL_allow_PCDATA, PCE_statement_template, &PCE_main_inst_template}, {NULL, NULL, NULL, 0, NULL}}; EIMIL_element_template PCE_docroot[] = {{"PCE", PCE_PCE_parser, NULL, EIMIL_element_single, PCE_template}, {NULL, NULL, NULL, 0, NULL}}; /******************************************************************************** PCE precompilation part *********************************************************************************/ enum PCE_inst { PCE_INVALID_INST = -1, PCE_NOP = 0, PCE_WHILE, PCE_GO, PCE_LABEL, PCE_UNDO, PCE_MARK_UNDO, PCE_TRY, PCE_THROW, PCE_IF, PCE_SELECT, PCE_TOGGLE_PREEDIT, PCE_TOGGLE_LOOKUP_CHOICE, PCE_KEYEVENTP, PCE_OR, PCE_AND, PCE_NOT, PCE_GT, PCE_LT, PCE_LE, PCE_GE, PCE_EQL, PCE_TBLKEYMAXSIZE, PCE_TBLVALMAXSIZE, PCE_PROPSIZE, PCE_PROPMBEG, PCE_PROPMEND, PCE_EVVAL, PCE_EVMOD, PCE_STRLEN, PCE_STRCMP, PCE_ADD, PCE_SUB, PCE_MUL, PCE_DIV, PCE_MOD, PCE_BOR, PCE_BAND, PCE_BXOR, PCE_UCSVAL, PCE_MAKEPROP, PCE_PROPADD, PCE_PROPCOPY, PCE_GETMPROP, PCE_FINDMPROP, PCE_EVCHAR, PCE_STRREF, PCE_MAKECHAR, PCE_INTERACT, PCE_MATCH, PCE_EVTYPE, PCE_EVMTEXT, PCE_CONCAT, PCE_SUBSTR, PCE_NEXT, PCE_FORWARD, PCE_SEND, PCE_MAKEEV, PCE_COMMIT, PCE_UNROLL, PCE_PROPDEL, PCE_ADDMPROP, PCE_DELMPROP, PCE_SETMPROP, PCE_SET, PCE_E, PCE_TBLREF }; static EIMIL_symbol* PCE_intern_soft( PCE_context *pctx, unsigned char *name ) { EIMIL_symbol *psym; psym = EIMIL_intern_soft(pctx->pdic, name); if (!psym) { psym = EIMIL_intern_soft(pctx->ped->pdic, name); } return psym; } static EIMIL_symbol* PCE_intern_soft_for_parser( PCE_parse_context *pcx, unsigned char *name ) { EIMIL_symbol *psym; PCE_context *pctx = pcx->pctx; if (pcx->pdic) psym = EIMIL_intern_soft(pcx->pdic, name); else psym = NULL; if (!psym) { psym = EIMIL_intern_soft(pctx->pdic, name); if (!psym) { psym = EIMIL_intern_soft(pctx->ped->pdic, name); } } return psym; } static EIMIL_symbol* PCE_register_symbol( PCE_context *pctx, unsigned char *name, enum EIMIL_CATEGORY cat, enum EIMIL_TYPE type ) { EIMIL_symbol *psym; psym = EIMIL_intern_soft(pctx->ped->pdic, name); if (!psym) { psym = EIMIL_register_symbol(pctx->ped, pctx->pdic, name, cat, type); if (psym) return psym; } EIMIL_set_error_pt(pctx->ped, NULL, "Duplicated symbol name:%s.", name); return NULL; } static EIMIL_symbol* PCE_get_variable( EIMIL_data *ped, PCE_parse_context *pcx, UTF8 *varname ) { EIMIL_symbol *psym; psym = PCE_intern_soft_for_parser(pcx, varname); if (!psym) { PCE_set_error(ped, PCE_PARSE_UNKNOWN_SYMBOL_ERROR); return NULL; } if (psym->cat != EIMIL_CAT_VARIABLE) { PCE_set_error(ped, PCE_NOT_VARIABLE_ERROR); return NULL; } return psym; } static EIMIL_symbol* PCE_get_function( EIMIL_data *ped, PCE_parse_context *pcx, UTF8 *varname ) { EIMIL_symbol *psym; psym = PCE_intern_soft_for_parser(pcx, varname); if (!psym) { PCE_set_error(ped, PCE_PARSE_UNKNOWN_SYMBOL_ERROR); return NULL; } if (psym->cat != EIMIL_CAT_FUNCTION) { PCE_set_error(ped, PCE_NOT_FUNCTION_ERROR); return NULL; } return psym; } static EIMIL_symbol* PCE_get_exception( EIMIL_data *ped, PCE_parse_context *pcx, UTF8 *varname ) { EIMIL_symbol *psym; psym = PCE_intern_soft_for_parser(pcx, varname); if (!psym) { PCE_set_error(ped, PCE_PARSE_UNKNOWN_SYMBOL_ERROR); return NULL; } if (psym->cat != EIMIL_CAT_EXCEPTION) { PCE_set_error(ped, PCE_NOT_EXCEPTION_ERROR); return NULL; } return psym; } static EIMIL_symbol* PCE_get_property( EIMIL_data *ped, PCE_parse_context *pcx, UTF8 *propname ) { EIMIL_symbol *psym; psym = PCE_intern_soft_for_parser(pcx, propname); if (!psym) { PCE_set_error(ped, PCE_PARSE_UNKNOWN_SYMBOL_ERROR); return NULL; } if (psym->cat != EIMIL_CAT_PROPERTY) { PCE_set_error(ped, PCE_NOT_EXCEPTION_ERROR); return NULL; } return psym; } static PCE_code* PCE_new_code_for_inst(PCE_EXEC_HANDLER h) { PCE_code *p; p = (PCE_code*) malloc(sizeof(PCE_code)); if (!p) return NULL; p->type = PCE_CODE_INST; p->val.h = h; p->parg = NULL; p->pnext = NULL; return p; } static PCE_code* PCE_new_code_for_value(EIMIL_value *pv) { PCE_code *p; p = (PCE_code*) malloc(sizeof(PCE_code)); if (!p) return NULL; p->type = PCE_CODE_VALUE; p->val.pv = pv; p->parg = NULL; p->pnext = NULL; return p; } static PCE_code* PCE_new_code_for_symbol( EIMIL_symbol *psym ) { PCE_code *p; p = (PCE_code*) malloc(sizeof(PCE_code)); if (!p) return NULL; p->type = PCE_CODE_SYMBOL; p->val.symid = psym->symbolid; p->parg = NULL; p->pnext = NULL; return p; } static PCE_code* PCE_new_code_for_function( PCE_function *pf ) { PCE_code *p; p = (PCE_code*) malloc(sizeof(PCE_code)); if (!p) return NULL; p->type = PCE_CODE_FUNCTION; p->val.pf = pf; p->parg = NULL; p->pnext = NULL; return p; } static PCE_code* PCE_new_code_for_etc( enum PCE_CODE_TYPE type ) { PCE_code *p; p = (PCE_code*) malloc(sizeof(PCE_code)); if (!p) return NULL; memset(p, 0, sizeof(PCE_code)); p->type = type; return p; } static PCE_code* PCE_new_code_for_jmp( enum PCE_CODE_TYPE jmptype, int id ) { PCE_code *p; p = (PCE_code*) malloc(sizeof(PCE_code)); if (!p) return NULL; memset(p, 0, sizeof(PCE_code)); ASSERT((jmptype == PCE_CODE_UNRESOLVED_JMP) || (jmptype == PCE_CODE_UNRESOLVED_COND_JMP) || (jmptype == PCE_CODE_UNRESOLVED_COND_NOT_JMP)); p->type = jmptype; p->val.to_labelid = id; return p; } static EIMIL_symbol* PCE_lookup_symbol( PCE_context *pctx, PCE_code *pc ) { EIMIL_symbol *psym; ASSERT((pc->type & PCE_CODE_SYMBOL) || (pc->type & PCE_CODE_DEFUN)); if (pctx->pdic_f) { psym = EIMIL_lookup_symbol_internal(pctx->pdic_f, pc->val.symid); if (psym) return psym; } psym = EIMIL_lookup_symbol_internal(pctx->pdic, pc->val.symid); if (psym) return psym; psym = EIMIL_lookup_symbol_internal(pctx->ped->pdic, pc->val.symid); return psym; } static EIMIL_value* PCE_symbol_value( PCE_context *pctx, PCE_code *pc ) { EIMIL_symbol *psym = PCE_lookup_symbol(pctx, pc); ASSERT(psym && psym->cat == EIMIL_CAT_VARIABLE); return psym->obj.v.pv; } static EIMIL_dictionary* PCE_new_dictionary( EIMIL_data *ped, PCE_context *pctx ) { EIMIL_symbol *psym; EIMIL_dictionary *pdic; pdic = EIMIL_new_dictionary(PCE_DICTIONARY_DEFAULT_SIZE, 1); if (!pdic) return NULL; /* internal variables */ psym = EIMIL_register_symbol(ped, pdic, "cev", EIMIL_CAT_VARIABLE, EIMIL_TYPE_EVENT); if (!psym) return NULL; psym->obj.v.type = EIMIL_TYPE_EVENT; psym->obj.v.constp = 1; psym->obj.v.pv = NULL; pctx->psym_cev = psym; psym = EIMIL_register_symbol(ped, pdic, "mapval", EIMIL_CAT_VARIABLE, EIMIL_TYPE_ANY); if (!psym) return NULL; psym->obj.v.type = EIMIL_TYPE_ANY; psym->obj.v.constp = 1; psym->obj.v.pv = NULL; pctx->pdic = pdic; return pdic; } static PCE_code* PCE_reverse_code( PCE_code *p ) { PCE_code *p1, *p2; if (!p) return NULL; p1 = NULL; for (;;) { p2 = p->pnext; p->pnext = p1; if (!p2) return p; p1 = p; p = p2; } /* notreached */ return NULL; } static enum EIMIL_TYPE PCE_get_type_from_name( UTF8 *name ) { if (strcmp(name, "bool") == 0) return EIMIL_TYPE_BOOL; else if (strcmp(name, "number") == 0) return EIMIL_TYPE_NUMBER; else if (strcmp(name, "char") == 0) return EIMIL_TYPE_CHAR; else if (strcmp(name, "mtext") == 0) return EIMIL_TYPE_MTEXT; else if (strcmp(name, "event") == 0) return EIMIL_TYPE_EVENT; else if (strcmp(name, "prop") == 0) return EIMIL_TYPE_PROP; return EIMIL_TYPE_INVALID; } #define TYPE_NAME_LEN_MAX 64 static int PCE_get_type_name( int type, char *buf, int len ) { char *tn = buf; buf[0] = '\0'; if (type & EIMIL_TYPE_ANY) { tn = "any type"; if (strlen(tn) >= len) return 0; strcpy(buf, tn); return 1; } if (type & EIMIL_TYPE_BOOL) { tn = "bool"; len -= strlen(tn); if (len <= 0) return 0; strcat(buf, tn); } if (type & EIMIL_TYPE_NUMBER) { if (*tn) tn = " or number"; else tn = "number"; len -= strlen(tn); if (len <= 0) return 0; strcat(buf, tn); } if (type & EIMIL_TYPE_CHAR) { if (*tn) tn = " or char"; else tn = "char"; len -= strlen(tn); if (len <= 0) return 0; strcat(buf, tn); } if (type & EIMIL_TYPE_MTEXT) { if (*tn) tn = " or mtext"; else tn = "mtext"; len -= strlen(tn); if (len <= 0) return 0; strcat(buf, tn); } if (type & EIMIL_TYPE_EVENT) { if (*tn) tn = " or event"; else tn = "event"; len -= strlen(tn); if (len <= 0) return 0; strcat(buf, tn); } if (type & EIMIL_TYPE_PROP) { if (*tn) tn = " or prop"; else tn = "prop"; len -= strlen(tn); if (len <= 0) return 0; strcat(buf, tn); } if (type & EIMIL_TYPE_NIL) { if (*tn) tn = " or nil"; else tn = "nil"; len -= strlen(tn); if (len <= 0) return 0; strcat(buf, tn); } return 1; } static void PCE_type_mismatch_error( EIMIL_data *ped, int type, int req ) { char mes_req[TYPE_NAME_LEN_MAX], mes_type[TYPE_NAME_LEN_MAX]; if (!PCE_get_type_name(req, mes_req, sizeof(mes_req))) return; if (!PCE_get_type_name(type, mes_type, sizeof(mes_type))) return; EIMIL_set_error_pt(ped, NULL, "Argument type is wrong.(%s, %s)", mes_req, mes_type); } static int PCE_check_type( EIMIL_data *ped, PCE_parse_context *pcx, int type ) { int i; int req; /* argument type */ if (pcx->mode & PCE_IN_E) { PCE_function *pf = pcx->pf; if (pf->nargs <= pcx->idx) { req = 0; } else { PCE_funcproto *pfp = pf->pfp + pcx->idx; req = pfp->type; } } else { for (i = 0; i <= pcx->idx; i++) { if (i >= PCE_ARG_MAX) { req = 0; break; } req = pcx->required_type[i]; if (!req) break; /* Note that EIMIL_TYPE_OPTION1 means it allows arbitrary number of arguments. */ if (req & EIMIL_TYPE_OPTION1) break; } } if (req == 0) { EIMIL_set_error_pt(ped, NULL, "Too many arguments."); return 0; } if ((req & EIMIL_TYPE_NIL) && (type == EIMIL_TYPE_NIL)) return 1; if ((req & EIMIL_TYPE_ANY) || (type & EIMIL_TYPE_ANY)) return 1; if ((req | type) == req) return 1; PCE_type_mismatch_error(ped, type, req); return 0; } static int PCE_setup_arg( EIMIL_data *ped, PCE_parse_context *pcx, PCE_code **ppc ) { int i, j, *pra; PCE_code *pc; /* Check the number of argument. */ if (pcx->mode & PCE_IN_E) { i = pcx->pf->nargs; } else { pra = pcx->required_type; for (i = 0; i <= PCE_ARG_MAX; i++, pra++) { if (!*pra) break; if (*pra | EIMIL_TYPE_OPTION2) break; if (*pra | EIMIL_TYPE_OPTION1) break; } } for (j = 0, pc = pcx->pc; pc; pc = pc->pnext, j++); if (j < i) { PCE_set_error(ped, PCE_TOO_FEW_ARGUMENTS_ERROR); return 0; } *ppc = PCE_reverse_code(pcx->pc); return 1; } static void PCE_free_code( PCE_code *pc ) { PCE_code *pc2; while (pc) { pc2 = pc->pnext; if (pc->parg) PCE_free_code(pc->parg); if (pc->type == PCE_CODE_VALUE) { EIMIL_RMREF(*pc->val.pv); } free(pc); pc = pc2; } } static void PCE_free_parse_context( PCE_parse_context *pcx ) { PCE_parse_context *pcx2; if (pcx->pc) PCE_free_code(pcx->pc); pcx2 = pcx->pnext; free(pcx); if (pcx2) PCE_free_parse_context(pcx2); } /***************************************** PCE label *****************************************/ #define PCE_LABEL_INITIALI_ALLOC_SIZE 16; static enum PCE_ERROR_CODE PCE_initialize_labels( PCE_parse_context *pcx ) { PCE_labelset *pls; pls = (PCE_labelset*) malloc(sizeof(PCE_labelset)); if (!pls) return PCE_MEMORY_ERROR; memset(pls, 0, sizeof(*pls)); pcx->plabels = pls; pls->pdic = EIMIL_new_dictionary(7, 0); if (!pls->pdic) { free(pls); return PCE_MEMORY_ERROR; } return PCE_SUCCESS; } static int PCE_make_label( PCE_parse_context *pcx ) { PCE_labelset *pls = pcx->plabels; PCE_label *pl; if (pls->allocednum <= pls->labelnum) { int newsize; if (pls->allocednum == 0) { newsize = PCE_LABEL_INITIALI_ALLOC_SIZE; } else { newsize = pls->allocednum * 2; } pl = (PCE_label*) realloc(pls->pl, sizeof(PCE_label) * newsize); if (!pl) return -1; pls->allocednum = newsize; pls->pl = pl; } pl = pls->pl + pls->labelnum; pl->id = pls->labelnum; pl->pc = NULL; pl->psym = NULL; pls->labelnum++; return pl->id; } static int PCE_make_named_label( EIMIL_data *ped, PCE_parse_context *pcx, UTF8 *name ) { int id; EIMIL_symbol *psym; PCE_labelset *pls = pcx->plabels; PCE_label *pl; id = PCE_make_label(pcx); if (id < 0) return id; pl = pls->pl + id; psym = EIMIL_register_symbol(ped, pls->pdic, name, EIMIL_CAT_OPTIONAL, EIMIL_TYPE_NONE); if (!psym) return -1; psym->obj.opt.optnum1 = id; pl->psym = psym; return id; } static int PCE_lookup_named_label( PCE_parse_context *pcx, UTF8 *name ) { int id; EIMIL_symbol *psym; PCE_labelset *pls = pcx->plabels; id = PCE_make_label(pcx); psym = EIMIL_intern_soft(pls->pdic, name); if (!psym) return -1; return psym->obj.opt.optnum1; } static void PCE_mark_label( PCE_parse_context *pcx, int id, PCE_code *pc, int nextp ) { PCE_labelset *pls = pcx->plabels; PCE_label *pl; ASSERT(id < pls->labelnum); pl = pls->pl + id; ASSERT(!pl->pc); pl->pc = pc; pl->nextp = nextp; } static void PCE_mark_label_yet( PCE_parse_context *pcx, int id, PCE_code *pc, int nextp ) { if (!((pcx->plabels->pl)[id].pc)) PCE_mark_label(pcx, id, pc, nextp); } static enum PCE_ERROR_CODE PCE_fixate_labels( EIMIL_data *ped, PCE_labelset *pls, PCE_code *pc_st ) { enum PCE_ERROR_CODE r; PCE_label *pl; PCE_code *pc; for (pc = pc_st; pc; pc = pc->pnext) { if ((pc->type == PCE_CODE_UNRESOLVED_JMP) || (pc->type == PCE_CODE_UNRESOLVED_COND_JMP) || (pc->type == PCE_CODE_UNRESOLVED_COND_NOT_JMP)) { ASSERT(pc->val.to_labelid < pls->labelnum); pl = pls->pl + pc->val.to_labelid; if (!pl->pc) { ASSERT(pl->psym); EIMIL_set_error(ped, "label:%s is not defined, but refered.", pl->psym->name); return PCE_LABEL_NOT_DEFINED_ERROR; } if (pc->type == PCE_CODE_UNRESOLVED_JMP) pc->type = PCE_CODE_JMP; else if (pc->type == PCE_CODE_UNRESOLVED_COND_JMP) pc->type = PCE_CODE_COND_JMP; else pc->type = PCE_CODE_COND_NOT_JMP; if (pl->nextp) pc->val.pc_to = pl->pc->pnext; else pc->val.pc_to = pl->pc; } if (pc->parg) { r = PCE_fixate_labels(ped, pls, pc->parg); if (r != PCE_SUCCESS) return r; } } return PCE_SUCCESS; } static enum PCE_ERROR_CODE PCE_finalize_labels( EIMIL_data *ped, PCE_parse_context *pcx ) { enum PCE_ERROR_CODE r; PCE_labelset *pls = pcx->plabels; r = PCE_fixate_labels(ped, pls, pcx->pc); if (r != PCE_SUCCESS) return r; EIMIL_free_dictionary_and_symbol(pls->pdic); free(pls->pl); free(pls); return PCE_SUCCESS; } /***************************************** literal *****************************************/ #define PCE_ischdec(c) (((c) >= '0' && (c) <= '9')) #define PCE_chdec(c) ((c) - '0') #define PCE_ischhex(c) (((c) >= '0' && (c) <= '9') \ || ((c) >= 'a' && (c) <= 'f') \ || ((c) >= 'A' && (c) <= 'F')) #define PCE_chhex(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \ ((c) >= 'a' && (c) <= 'f') ? ((c) - 'a') : ((c) - 'A')) static enum PCE_ERROR_CODE PCE_parse_literal( EIMIL_data *ped, UTF8 *pchars, EIMIL_value **ppv ) { EIMIL_value *pv; if ((*pchars >= '1') && (*pchars <= '9')) { /* DEC NUMBER */ int n = 0; for (; *pchars; pchars++) { if (!PCE_ischdec(*pchars)) { PCE_set_error(ped, PCE_DEC_NUMBER_ERROR); return PCE_DEC_NUMBER_ERROR; } n = n * 10 + PCE_chdec(*pchars); if (n > PCE_MAX_NUMBER) { PCE_set_error(ped, PCE_LITERAL_OVERFLOW); return PCE_LITERAL_OVERFLOW; } } pv = EIMIL_construct_number(n); } else if (*pchars == '0') { int n; if (pchars[1] == '\0') { n = 0; } else { /* HEX NUMBER */ if (pchars[1] != 'x') { PCE_set_error(ped, PCE_HEX_NUMBER_ERROR); return PCE_HEX_NUMBER_ERROR; } pchars += 2; n = 0; for (; *pchars; pchars++) { if (!PCE_ischhex(*pchars)) { PCE_set_error(ped, PCE_HEX_NUMBER_ERROR); return PCE_HEX_NUMBER_ERROR; } n = n * 10 + PCE_chhex(*pchars); if (n > PCE_MAX_NUMBER) { PCE_set_error(ped, PCE_LITERAL_OVERFLOW); return PCE_LITERAL_OVERFLOW; } } } pv = EIMIL_construct_number(n); } else if (*pchars == '\'') { /* CHAR */ UTF32 ch; int n = EIMIL_convert_UTF8_to_UTF32char(pchars + 1, &ch); if ((pchars[n + 1] != '\'') || (pchars[n + 2] != 0)) { PCE_set_error(ped, PCE_CHAR_LITERAL_ERROR); return PCE_CHAR_LITERAL_ERROR; } pv = EIMIL_construct_char(ch); } else if (*pchars == '"') { /* MTEXT */ UTF32 *pu32; int n = strlen(pchars); if (pchars[n - 1] != '"') { PCE_set_error(ped, PCE_MTEXT_LITERAL_ERROR); return PCE_MTEXT_LITERAL_ERROR; } pchars[n - 1] = 0; pu32 = EIMIL_convert_UTF8_to_UTF32(pchars + 1); pv = EIMIL_construct_mtext_from_UTF32(n - 2, pu32); free(pu32); } else { return PCE_PARSE_NOT_LITERAL; } if (!pv) { PCE_set_error(ped, PCE_MEMORY_ERROR); return PCE_MEMORY_ERROR; } *ppv = pv; return PCE_SUCCESS; } static enum PCE_ERROR_CODE PCE_parse_token( EIMIL_data *ped, PCE_parse_context *pcx, UTF8 *pchars ) { EIMIL_value *pv; enum PCE_ERROR_CODE r; r = PCE_parse_literal(ped, pchars, &pv); switch (r) { case PCE_SUCCESS: { PCE_code *pc; if (!PCE_check_type(ped, pcx, pv->type)) return PCE_WRONG_TYPE_ARGUMENT_ERROR; pc = PCE_new_code_for_value(pv); if (!pc) { PCE_set_error(ped, PCE_MEMORY_ERROR); return PCE_MEMORY_ERROR; } EIMIL_ADDREF(*pv); PCE_ADD_CODE(pcx, pc); return PCE_SUCCESS; } case PCE_PARSE_NOT_LITERAL: { /* maybe VARIABLE */ PCE_code *pc; EIMIL_symbol *psym; psym = PCE_get_variable(ped, pcx, pchars); if (!psym) return PCE_MEMORY_ERROR; if (!PCE_check_type(ped, pcx, psym->obj.v.type)) return PCE_WRONG_TYPE_ARGUMENT_ERROR; pc = PCE_new_code_for_symbol(psym); if (!pc) return PCE_MEMORY_ERROR; PCE_ADD_CODE(pcx, pc); return PCE_SUCCESS; } default: break; } return r; } static enum EIMIL_TYPE PCE_get_type_from_attrs( EIMIL_data *ped, EIMIL_attrs *patr ) { UTF8 *name; enum EIMIL_TYPE type; for (; patr->name; patr++) { if (strcmp(patr->name, "type") == 0) { if (!EIMIL_get_attr_nmtoken(patr->val, &name)) { type = EIMIL_TYPE_INVALID; break; } type = PCE_get_type_from_name(name); free(name); free(patr->name); free(patr->val); EIMIL_remove_attr(patr); break; } } if (type == EIMIL_TYPE_INVALID) { EIMIL_set_error_pt(ped, NULL, "Invalid type name:%s", patr->name); } return type; } /**************************************** parser handlers ****************************************/ static PCE_parse_context* PCE_parser_decl_start( EIMIL_data *ped, PCE_parse_context *pcx ) { /* TODO */ return NULL; } static PCE_parse_context* PCE_new_parse_context( EIMIL_data *ped ) { PCE_parse_context *pcnx; pcnx = (PCE_parse_context*) malloc(sizeof(PCE_parse_context)); if (!pcnx) { EIMIL_set_out_of_memory(ped); return NULL; } memset(pcnx, 0, sizeof(PCE_parse_context)); return pcnx; } static PCE_parse_context* PCE_parser_generic_start( EIMIL_data *ped, PCE_parse_context *pcx, int type ) { PCE_parse_context *pcnx; if (!PCE_check_type(ped, pcx, type)) return NULL; pcnx = PCE_new_parse_context(ped); if (!pcnx) return NULL; /* already done: pcnx->idx = 0; */ pcnx->pnext = pcx; pcnx->result = type; pcnx->pctx = pcx->pctx; pcnx->mode = pcx->mode; pcnx->pdic = pcx->pdic; pcnx->pf = pcx->pf; pcnx->plabels = pcx->plabels; return pcnx; } static PCE_parse_context* PCE_parser_generic_end( EIMIL_data *ped, PCE_parse_context *pcx, PCE_code *pc ) { PCE_parse_context *pcx2; if (!pc) { EIMIL_set_out_of_memory(ped); PCE_free_parse_context(pcx); return NULL; } pcx2 = pcx->pnext; if (!PCE_setup_arg(ped, pcx, &pc->parg)) { PCE_free_parse_context(pcx); return NULL; } PCE_ADD_CODE(pcx2, pc); free(pcx); return pcx2; } static PCE_code* PCE_insert_head_code( PCE_code *pc, PCE_code *pc_ins, int first_argp ) { PCE_code *pc2, *pc_end, *pc_prevend; pc_end = pc_prevend = NULL; for (pc2 = pc; pc2; pc2 = pc2->pnext) { pc_prevend = pc_end; pc_end = pc2; } if (first_argp) { ASSERT(pc_end); pc_ins->parg = pc_end; if (pc_prevend) pc_prevend->pnext = pc_ins; pc_ins->parg->pnext = NULL; } else { if (pc_end) pc_end->pnext = pc_ins; else return pc_ins; } return pc; } enum PCE_JMP_END_FLAG { PCE_UNCOND_JMP_END, PCE_COND_JMP_END, PCE_COND_NOT_JMP_END }; static PCE_parse_context* PCE_parser_jmp_end( EIMIL_data *ped, PCE_parse_context *pcx, enum PCE_JMP_END_FLAG condflag, int loopp ) { int cflag; PCE_parse_context *pcx2; PCE_code *pc, *pc2; if (condflag == PCE_UNCOND_JMP_END) { pc = PCE_new_code_for_jmp(PCE_CODE_UNRESOLVED_JMP, pcx->labelid); cflag = 0; } else if (condflag == PCE_COND_JMP_END) { pc = PCE_new_code_for_jmp(PCE_CODE_UNRESOLVED_COND_JMP, pcx->labelid); cflag = 1; } else { pc = PCE_new_code_for_jmp(PCE_CODE_UNRESOLVED_COND_NOT_JMP, pcx->labelid); cflag = 1; } if (!pc) { EIMIL_set_out_of_memory(ped); PCE_free_parse_context(pcx); return NULL; } if (cflag && !pcx->pc) { PCE_set_error(ped, PCE_TOO_FEW_ARGUMENTS_ERROR); return NULL; } pc2 = PCE_insert_head_code(pcx->pc, pc, cflag); pcx2 = pcx->pnext; pc->pnext = pcx2->pc; if (loopp) { int loopid; PCE_code *pc_loop; loopid = PCE_make_label(pcx2); if (loopid < 0) return NULL; pc_loop = PCE_new_code_for_jmp(PCE_CODE_UNRESOLVED_JMP, loopid); if (!pc_loop) return NULL; pc_loop->pnext = pc2; pcx2->pc = pc_loop; PCE_mark_label(pcx2, loopid, pc, 0); } else { pcx2->pc = pc2; } free(pcx); return pcx2; } static PCE_parse_context* PCE_parser_select_case_end( EIMIL_data *ped, PCE_parse_context *pcx ) { PCE_parse_context *pcx2; PCE_code *pc_case_cond, *pc_jmp_to_tail; pcx2 = pcx->pnext; pc_case_cond = PCE_new_code_for_jmp(PCE_CODE_UNRESOLVED_COND_JMP, pcx->labelid2); pc_jmp_to_tail = PCE_new_code_for_jmp(PCE_CODE_UNRESOLVED_JMP, pcx2->labelid); if ((!pc_case_cond) || (!pc_jmp_to_tail)) { EIMIL_set_out_of_memory(ped); PCE_free_parse_context(pcx); return NULL; } PCE_ADD_CODE(pcx, pc_jmp_to_tail); { PCE_code *pc2, *pc_end, *pc_prevend; pc_end = pc_prevend = NULL; for (pc2 = pcx->pc; pc2; pc2 = pc2->pnext) { pc_prevend = pc_end; pc_end = pc2; } if (!(pc_end && pc_prevend)) { PCE_set_error(ped, PCE_TOO_FEW_ARGUMENTS_ERROR); return NULL; } pc_case_cond->parg = pc_end; pc_case_cond->pnext = pcx2->pc_head; pcx2->pc_head = pc_case_cond; pc_prevend->pnext = pcx2->pc; pcx2->pc = pcx->pc; PCE_mark_label(pcx2, pcx->labelid2, pc_prevend, 0); } free(pcx); return pcx2; } static PCE_parse_context* PCE_parser_select_default_end( EIMIL_data *ped, PCE_parse_context *pcx ) { PCE_parse_context *pcx2; PCE_code *pc_def_jmp; pcx2 = pcx->pnext; if (pcx->pc) { PCE_code *pc2, *pc_end; pc_def_jmp = PCE_new_code_for_jmp(PCE_CODE_UNRESOLVED_JMP, pcx->labelid2); if (!pc_def_jmp) { EIMIL_set_out_of_memory(ped); return NULL; } pc_end = NULL; for (pc2 = pcx->pc; pc2; pc2 = pc2->pnext) { pc_end = pc2; } PCE_mark_label(pcx2, pcx->labelid2, pc_end, 0); pc_end->pnext = pcx2->pc; pcx2->pc = pc_end; pcx2->mode |= PCE_SELECT_HAS_DEFAULT; } else { pc_def_jmp = PCE_new_code_for_jmp(PCE_CODE_UNRESOLVED_JMP, pcx->labelid); } pc_def_jmp->pnext = pcx2->pc_head; pcx2->pc_head = pc_def_jmp; free(pcx); return pcx2; } static PCE_parse_context* PCE_parser_select_end( EIMIL_data *ped, PCE_parse_context *pcx ) { PCE_parse_context *pcx2; PCE_code *pc_cond_end; PCE_code *pc_block_end; pcx2 = pcx->pnext; pc_cond_end = pcx->pc_head; pc_block_end = pcx->pc; if (!(pcx->mode & PCE_SELECT_HAS_DEFAULT)) { PCE_code *pc = PCE_new_code_for_jmp(PCE_CODE_UNRESOLVED_JMP, pcx->labelid); if (!pc) return NULL; pc->pnext = pc_cond_end; pc_cond_end = pc; } pc_block_end = PCE_insert_head_code(pc_block_end, pc_cond_end, 0); pcx2->pc = PCE_insert_head_code(pc_block_end, pcx2->pc, 0); PCE_mark_label_yet(pcx, pcx->labelid, pcx2->pc, 1); free(pcx); return pcx2; } /* attribute access */ static UTF8* PCE_get_name_attribute( EIMIL_data *ped, EIMIL_attrs *patr ) { UTF8 *name; for (; patr->name;patr++) { if (strcmp(patr->name, "name") == 0) { if (!EIMIL_get_attr_nmtoken(patr->val, &name)) { EIMIL_set_error_pt(ped, NULL, "Invalid nmtoken in `name'"); return NULL; } return name; } } return NULL; } enum PCE_VAL_TYPE { PCE_VAL_TYPE_INVALID, PCE_VAL_TYPE_NIL, PCE_VAL_TYPE_CONST, PCE_VAL_TYPE_INIT }; static enum PCE_VAL_TYPE PCE_get_val_type_attribute( EIMIL_data *ped, EIMIL_attrs *patr ) { for (; patr->name; patr++) { if (strcmp(patr->name, "val") == 0) { enum PCE_VAL_TYPE vt; UTF8 *val; if (!EIMIL_get_attr_nmtoken(patr->val, &val)) { EIMIL_set_error_pt(ped, NULL, "Unrecogized keyword in `val'"); return PCE_VAL_TYPE_INVALID; } if (strcmp(val, "const") == 0) { vt = PCE_VAL_TYPE_CONST; } else if (strcmp(val, "nil") == 0) { vt = PCE_VAL_TYPE_NIL; } else if (strcmp(val, "init") == 0) { vt = PCE_VAL_TYPE_INIT; } else { vt = PCE_VAL_TYPE_INVALID; } free(val); return vt; } } return PCE_VAL_TYPE_INVALID; } #define PCE_ARGUMENT_DICTIONARY_SIZE 5 static int PCE_get_funcproto_attribute( EIMIL_data *ped, EIMIL_attrs *patr, PCE_function **ppf ) { for (; patr->name;patr++) { if (strcmp(patr->name, "args") == 0) { enum EIMIL_TYPE type; UTF8 *argname, *typename; EIMIL_dictionary *pdic = NULL; EIMIL_symbol *psym; PCE_function *pf; PCE_funcproto *pfp, *pfp2; Ebyte *c = patr->val; int i = 0; int n = 0; pfp2 = pfp = NULL; while ((c = EIMIL_get_attr_nmtokens(c, &argname)) != NULL) { if (i >= n) { n += 10; pfp2 = (PCE_funcproto*) realloc(pfp2, sizeof(PCE_funcproto) * n); if (!pfp2) { PCE_set_error(ped, PCE_MEMORY_ERROR); return 0; } pfp = pfp2 + i; } typename = strchr(argname, ':'); if (!typename) { EIMIL_set_error_pt(ped, NULL, "Function argument must specify type name."); return 0; } *typename = '\0'; typename++; type = PCE_get_type_from_name(typename); if (type == EIMIL_TYPE_INVALID) { EIMIL_set_error_pt(ped, NULL, "Invalid type name:%s.", typename); return 0; } pfp->type = type; if (!pdic) { pdic = EIMIL_new_dictionary(PCE_ARGUMENT_DICTIONARY_SIZE, 1); if (!pdic) { PCE_set_error(ped, PCE_MEMORY_ERROR); return 0; } } psym = EIMIL_register_symbol(ped, pdic, argname, EIMIL_CAT_VARIABLE, type); pfp->psym = psym; pfp++; i++; } if (i > 0) { pfp = (PCE_funcproto*) realloc(pfp2, sizeof(PCE_funcproto) * i); if (!pfp) { PCE_set_error(ped, PCE_MEMORY_ERROR); return 0; } } pf = (PCE_function*) malloc(sizeof(PCE_function)); if (!pf) { PCE_set_error(ped, PCE_MEMORY_ERROR); return 0; } memset(pf, 0, sizeof(PCE_function)); pf->nargs = i; pf->pdic = pdic; pf->pfp = pfp; pf->pc = NULL; *ppf = pf; return 1; } } return 0; } /* declaration. */ DEFINE_PARSER_METHOD(defvar) { PCE_parse_context *pcx = (PCE_parse_context*) *pprivate; switch (type) { case EIMIL_START_TAG: { int constp = 0; enum PCE_VAL_TYPE vt; EIMIL_symbol *psym; char *name; type = PCE_get_type_from_attrs(ped, patr); if (type == EIMIL_TYPE_INVALID) return 0; vt = PCE_get_val_type_attribute(ped, patr); if (vt == PCE_VAL_TYPE_INVALID) return 0; name = PCE_get_name_attribute(ped, patr); if (!name) return 0; if (vt == PCE_VAL_TYPE_CONST) { constp = 1; } else if (vt == PCE_VAL_TYPE_NIL) { pcx->mode = PCE_SET_PARSER_CONTEXT_MODE(pcx, PCE_DEFVAR_NIL); } psym = PCE_register_symbol(pcx->pctx, name, EIMIL_CAT_VARIABLE, type); free(name); if (!psym) return 0; psym->publicp = 0; psym->obj.v.constp = constp; psym->obj.v.type = type; psym->obj.v.pv = NULL; pcx->psym = psym; return 1; } case EIMIL_CHARDATA: { EIMIL_value *pv; EIMIL_symbol *psym = pcx->psym; enum PCE_ERROR_CODE r; if (pcx->mode & PCE_DEFVAR_DONE) { PCE_set_error(ped, PCE_DEFVAR_DONE_ERROR); return 0; } if (pcx->mode & PCE_DEFVAR_NIL) { PCE_set_error(ped, PCE_DEFVAR_NIL_ERROR); return 0; } r = PCE_parse_literal(ped, pchars, &pv); if (r != PCE_SUCCESS) { PCE_set_error(ped, r); return 0; } if (psym->obj.v.type != pv->type) { PCE_type_mismatch_error(ped, psym->obj.v.type, pv->type); return 0; } psym = pcx->psym; ASSERT(psym); pcx->psym->obj.v.pv = pv; EIMIL_ADDREF(*pv); pcx->mode = PCE_SET_PARSER_CONTEXT_MODE(pcx, PCE_DEFVAR_DONE); return 1; } case EIMIL_END_TAG: pcx->mode = PCE_RESET_PARSER_CONTEXT_MODE(pcx, PCE_DEFVAR_NIL_ERROR | PCE_DEFVAR_DONE); return 1; default: EIMIL_set_error_pt(ped, NULL, "Unknown error."); } return 0; } DEFINE_PARSER_METHOD(defun) { PCE_parse_context *pcx = (PCE_parse_context*) *pprivate; PCE_inst_template *pit = (PCE_inst_template*) ped->pcommon->ps.pcet->private; switch (type) { case EIMIL_START_TAG: { PCE_function *pf; EIMIL_symbol *psym; char *name; enum EIMIL_TYPE rettype; rettype = PCE_get_type_from_attrs(ped, patr); if (rettype == EIMIL_TYPE_INVALID) return 0; name = PCE_get_name_attribute(ped, patr); if (!name) return 0; if (!PCE_get_funcproto_attribute(ped, patr, &pf)) return 0; pf->rettype = rettype; psym = PCE_register_symbol(pcx->pctx, name, EIMIL_CAT_FUNCTION, type); free(name); if (!psym) return 0; psym->publicp = 0; psym->obj.f.type = type; psym->obj.f.def = pf; pcx = PCE_parser_generic_start(ped, pcx, pit->result); if (!pcx) return 0; PCE_SET_REQUIRED_TYPES(pcx, pit); pcx->mode = PCE_NEW_PARSER_CONTEXT_MODE(pcx, PCE_IN_DEFUN); pcx->psym = psym; pcx->pdic = pf->pdic; pcx->pf = pf; *pprivate = pcx; return 1; } case EIMIL_CHARDATA: EIMIL_set_error(ped, NULL, "The expression has no effect."); return 0; case EIMIL_END_TAG: { EIMIL_symbol *psym = pcx->psym; PCE_function *pf = (PCE_function*) psym->obj.f.def; int symid; symid = pcx->psym->symbolid; pcx = PCE_parser_generic_end(ped, pcx, PCE_new_code_for_etc(PCE_CODE_DEFUN)); pcx->pc->val.symid = symid; if (!pcx) return 0; pf->pc = pcx->pc; return 1; } default: EIMIL_set_error_pt(ped, NULL, "Unknown error."); } return 0; } DEFINE_PARSER_METHOD(main) { PCE_parse_context *pcx = (PCE_parse_context*) *pprivate; PCE_inst_template *pit = (PCE_inst_template*) ped->pcommon->ps.pcet->private; switch (type) { case EIMIL_START_TAG: { pcx = PCE_parser_generic_start(ped, pcx, pit->result); if (!pcx) return 0; PCE_SET_REQUIRED_TYPES(pcx, pit); pcx->mode = PCE_NEW_PARSER_CONTEXT_MODE(pcx, PCE_IN_MAIN); *pprivate = pcx; return 1; } case EIMIL_CHARDATA: EIMIL_set_error(ped, NULL, "The expression has no effect."); return 0; case EIMIL_END_TAG: { PCE_data *pd = pcx->pctx->ppce_data; pcx = PCE_parser_generic_end(ped, pcx, PCE_new_code_for_etc(PCE_CODE_MAIN)); if (!pcx) return 0; pd->pcode = pcx->pc; return 1; } default: EIMIL_set_error_pt(ped, NULL, "Unknown error."); } return 0; } DEFINE_PARSER_METHOD(deftable) { /* TODO */ return 1; } DEFINE_PARSER_METHOD(key) { return 0; } DEFINE_PARSER_METHOD(defkeymap) { /* TODO */ return 1; } DEFINE_PARSER_METHOD(mnemonic) { /* TODO */ return 1; } DEFINE_PARSER_METHOD(pattern) { /* TODO */ return 1; } DEFINE_PARSER_METHOD(defpattern) { /* TODO */ return 1; } /* generic parser */ static int PCE_generic_inst_parser( EIMIL_data *ped, EIMIL_attrs *patr, enum EIMIL_TAG_TYPE type, UTF8 *pchars, void **pprivate ) { PCE_parse_context *pcx = (PCE_parse_context*) *pprivate; PCE_inst_template *pit = (PCE_inst_template*) ped->pcommon->ps.pcet->private; switch (type) { case EIMIL_START_TAG: pcx = PCE_parser_generic_start(ped, pcx, pit->result); if (!pcx) return 0; PCE_SET_REQUIRED_TYPES(pcx, pit); if ((pit->newmode & PCE_ONLY_IN_MAIN_STATEMENT) && !(pcx->mode & PCE_IN_MAIN)) { EIMIL_set_error_pt(ped, NULL, "`%s' element must be in `main' element.", ped->pcommon->ps.pcet->name); return 0; } pcx->mode = PCE_NEW_PARSER_CONTEXT_MODE(pcx, pit->newmode); *pprivate = pcx; return 1; case EIMIL_CHARDATA: if (PCE_parse_token(ped, pcx, pchars) == PCE_SUCCESS) return 1; return 0; case EIMIL_END_TAG: if (pit->code_type == PCE_CODE_INST) pcx = PCE_parser_generic_end(ped, pcx, PCE_new_code_for_inst(pit->handler)); else pcx = PCE_parser_generic_end(ped, pcx, PCE_new_code_for_etc(pit->code_type)); if (!pcx) return 0; return 1; default: EIMIL_set_error_pt(ped, NULL, "Unknown error."); } return 0; } /* return element */ DEFINE_PARSER_METHOD(return) { PCE_parse_context *pcx = (PCE_parse_context*) *pprivate; if (type == EIMIL_START_TAG) { int r; if (!(pcx->mode & PCE_IN_DEFUN)) { PCE_set_error(ped, PCE_PARSE_RETURN_IN_DEFUN_ERROR); } r = PCE_generic_inst_parser(ped, patr, type, pchars, pprivate); ASSERT(pcx->pf); pcx->required_type[0] = pcx->pf->rettype; return r; } return PCE_generic_inst_parser(ped, patr, type, pchars, pprivate); } /* flow control */ DEFINE_PARSER_METHOD(if) { int id; PCE_parse_context *pcx = (PCE_parse_context*) *pprivate; switch (type) { case EIMIL_START_TAG: id = PCE_make_label(pcx); if (id < 0) return 0; pcx = PCE_parser_generic_start(ped, pcx, EIMIL_TYPE_NONE); if (!pcx) return 0; pcx->required_type[0] = EIMIL_TYPE_ANY; pcx->required_type[1] = EIMIL_TYPE_ANY | EIMIL_TYPE_OPTION1; pcx->mode = PCE_NEW_PARSER_CONTEXT_MODE(pcx, PCE_IN_IF); pcx->labelid = pcx->labelid2 = id; *pprivate = pcx; return 1; case EIMIL_CHARDATA: if (PCE_parse_token(ped, pcx, pchars) == PCE_SUCCESS) return 1; return 0; case EIMIL_END_TAG: { int st_label_id = pcx->labelid2; pcx = PCE_parser_jmp_end(ped, pcx, PCE_COND_NOT_JMP_END, 0); if (!pcx) return 0; PCE_mark_label_yet(pcx, st_label_id, pcx->pc, 1); return 1; } default: break; } return 0; } DEFINE_PARSER_METHOD(else) { PCE_parse_context *pcx = (PCE_parse_context*) *pprivate; switch (type) { case EIMIL_START_TAG: { int id; PCE_code *pc; id = PCE_make_label(pcx); if (id < 0) return 0; pc = PCE_new_code_for_jmp(PCE_CODE_UNRESOLVED_JMP, id); if (!pc) return 0; PCE_ADD_CODE(pcx, pc); PCE_mark_label(pcx, pcx->labelid, pc, 1); pcx->labelid2 = id; return 1; } case EIMIL_CHARDATA: if (PCE_parse_token(ped, pcx, pchars) == PCE_SUCCESS) return 1; return 0; case EIMIL_END_TAG: return 1; default: break; } return 0; } DEFINE_PARSER_METHOD(while) { int id; PCE_parse_context *pcx = (PCE_parse_context*) *pprivate; switch (type) { case EIMIL_START_TAG: id = PCE_make_label(pcx); if (id < 0) return 0; pcx = PCE_parser_generic_start(ped, pcx, EIMIL_TYPE_NONE); if (!pcx) return 0; pcx->required_type[0] = EIMIL_TYPE_ANY | EIMIL_TYPE_OPTION1; pcx->mode = PCE_NEW_PARSER_CONTEXT_MODE(pcx, PCE_IN_IF); pcx->labelid = id; *pprivate = pcx; return 1; case EIMIL_CHARDATA: if (PCE_parse_token(ped, pcx, pchars) == PCE_SUCCESS) return 1; return 0; case EIMIL_END_TAG: { int st_label_id = pcx->labelid; pcx = PCE_parser_jmp_end(ped, pcx, PCE_COND_NOT_JMP_END, 1); if (!pcx) return 0; PCE_mark_label_yet(pcx, st_label_id, pcx->pc, 1); return 1; } default: break; } return 0; } DEFINE_PARSER_METHOD(case) { PCE_parse_context *pcx = (PCE_parse_context*) *pprivate; switch (type) { case EIMIL_START_TAG: { int id; id = PCE_make_label(pcx); if (id < 0) return 0; pcx = PCE_parser_generic_start(ped, pcx, EIMIL_TYPE_NONE); if (!pcx) return 0; pcx->required_type[0] = EIMIL_TYPE_ANY; pcx->required_type[1] = EIMIL_TYPE_ANY | EIMIL_TYPE_OPTION1; pcx->mode = PCE_NEW_PARSER_CONTEXT_MODE(pcx, PCE_IN_SELECT); pcx->labelid2 = id; *pprivate = pcx; return 1; } case EIMIL_CHARDATA: if (PCE_parse_token(ped, pcx, pchars) == PCE_SUCCESS) return 1; return 0; case EIMIL_END_TAG: pcx = PCE_parser_select_case_end(ped, pcx); if (!pcx) return 0; return 1; default: break; } return 0; } DEFINE_PARSER_METHOD(default) { PCE_parse_context *pcx = (PCE_parse_context*) *pprivate; switch (type) { case EIMIL_START_TAG: { int id; id = PCE_make_label(pcx); if (id < 0) return 0; pcx = PCE_parser_generic_start(ped, pcx, EIMIL_TYPE_NONE); if (!pcx) return 0; pcx->required_type[0] = EIMIL_TYPE_ANY | EIMIL_TYPE_OPTION1; pcx->mode = PCE_NEW_PARSER_CONTEXT_MODE(pcx, PCE_IN_SELECT); pcx->labelid2 = id; *pprivate = pcx; return 1; } case EIMIL_CHARDATA: if (PCE_parse_token(ped, pcx, pchars) == PCE_SUCCESS) return 1; return 0; case EIMIL_END_TAG: pcx = PCE_parser_select_default_end(ped, pcx); if (!pcx) return 0; return 1; default: break; } return 0; } DEFINE_PARSER_METHOD(select) { int id; PCE_parse_context *pcx = (PCE_parse_context*) *pprivate; switch (type) { case EIMIL_START_TAG: id = PCE_make_label(pcx); /* label for the tail. */ if (id < 0) return 0; pcx = PCE_parser_generic_start(ped, pcx, EIMIL_TYPE_NONE); if (!pcx) return 0; pcx->required_type[0] = EIMIL_TYPE_ANY | EIMIL_TYPE_OPTION1; pcx->mode = PCE_NEW_PARSER_CONTEXT_MODE(pcx, PCE_IN_SELECT); pcx->labelid = id; pcx->pc_head = NULL; /* Used for the head jmp table(s). */ *pprivate = pcx; return 1; case EIMIL_CHARDATA: return 0; case EIMIL_END_TAG: { pcx = PCE_parser_select_end(ped, pcx); if (!pcx) return 0; return 1; } default: break; } return 0; } /* SEH */ DEFINE_PARSER_METHOD(try) { /* TODO */ return 1; } /* inst with attr. */ /* exc attr */ static EIMIL_symbol* PCE_attr_get_exception_symbol( EIMIL_data *ped, PCE_parse_context *pcx, EIMIL_attrs *patr ) { for (; patr->name;patr++) { if (strcmp(patr->name, "exc") == 0) { EIMIL_symbol *psym; UTF8 *name; if (!EIMIL_get_attr_nmtokens(patr->val, &name)) { EIMIL_set_error_pt(ped, NULL, "Unrecogized keyword in `v'"); return NULL; } psym = PCE_get_exception(ped, pcx, name); free(name); if (!psym) return NULL; return psym; } } return NULL; } DEFINE_PARSER_METHOD(throw) { if (type != EIMIL_EMPTY_TAG) return 0; { PCE_parse_context *pcx = (PCE_parse_context*) *pprivate; EIMIL_symbol *psym; PCE_code *pc, *pc_arg; psym = PCE_attr_get_exception_symbol(ped, pcx, patr); pc_arg = PCE_new_code_for_symbol(pcx->psym); if (!pc_arg) { PCE_set_error(ped, PCE_MEMORY_ERROR); return 0; } pc = PCE_new_code_for_inst(PCE_throw_exec); if (!pc) { PCE_set_error(ped, PCE_MEMORY_ERROR); return 0; } pc->parg = pc_arg; PCE_ADD_CODE(pcx, pc); } return 1; } DEFINE_PARSER_METHOD(catch) { PCE_parse_context *pcx = (PCE_parse_context*) *pprivate; switch (type) { case EIMIL_START_TAG: { EIMIL_symbol *psym; psym = PCE_attr_get_exception_symbol(ped, pcx, patr); pcx = PCE_parser_generic_start(ped, pcx, EIMIL_TYPE_NONE); if (!pcx) return 0; pcx->required_type[0] = EIMIL_TYPE_ANY | EIMIL_TYPE_OPTION1; pcx->mode = PCE_NEW_PARSER_CONTEXT_MODE(pcx, 0); pcx->psym = psym; *pprivate = pcx; return 1; } case EIMIL_CHARDATA: if (PCE_parse_token(ped, pcx, pchars) == PCE_SUCCESS) return 1; return 0; case EIMIL_END_TAG: { PCE_code *pc = PCE_new_code_for_symbol(pcx->psym); if (!pc) { PCE_set_error(ped, PCE_MEMORY_ERROR); return 0; } pcx = PCE_parser_generic_end(ped, pcx, PCE_new_code_for_inst(PCE_catch_exec)); /* Insert EIMIL_exception symbol to the first argument of `catch'. */ pc->pnext = pcx->pc->parg; pcx->pc->parg = pc; if (!pcx) return 0; return 1; } default: break; } return 0; } /* exc attr */ static UTF8* PCE_attr_get_label_symbol( EIMIL_data *ped, PCE_parse_context *pcx, EIMIL_attrs *patr ) { for (; patr->name;patr++) { if (strcmp(patr->name, "to") == 0) { UTF8 *name; if (!EIMIL_get_attr_nmtokens(patr->val, &name)) { EIMIL_set_error_pt(ped, NULL, "Unrecogized keyword in `v'"); return NULL; } return name; } } return NULL; } DEFINE_PARSER_METHOD(go) { int id; UTF8* labelname; PCE_code *pc; PCE_parse_context *pcx = (PCE_parse_context*) *pprivate; ASSERT(type == EIMIL_EMPTY_TAG); if (!(pcx->mode & PCE_IN_MAIN)) { EIMIL_set_error_pt(ped, NULL, "`go' element must be in `main' element."); return 0; } labelname = PCE_attr_get_label_symbol(ped, pcx, patr); if (!labelname) return 0; id = PCE_lookup_named_label(pcx, labelname); if (id < 0) { id = PCE_make_named_label(ped, pcx, labelname); if (id < 0) { free(labelname); return 0; } } free(labelname); pc = PCE_new_code_for_jmp(PCE_CODE_UNRESOLVED_JMP, id); PCE_ADD_CODE(pcx, pc); return 1; } DEFINE_PARSER_METHOD(label) { int id; UTF8* labelname; PCE_parse_context *pcx = (PCE_parse_context*) *pprivate; ASSERT(type == EIMIL_EMPTY_TAG); if (!(pcx->mode & PCE_IN_MAIN)) { EIMIL_set_error_pt(ped, NULL, "`label' element must be in `main' element."); return 0; } labelname = PCE_attr_get_label_symbol(ped, pcx, patr); if (!labelname) return 0; id = PCE_lookup_named_label(pcx, labelname); if (id < 0) { id = PCE_make_named_label(ped, pcx, labelname); if (id < 0) return 0; } PCE_mark_label(pcx, id, pcx->pc, 1); return 1; } DEFINE_PARSER_METHOD(tblkeymaxsize) { return 1; } DEFINE_PARSER_METHOD(tblvalmaxsize) { return 1; } DEFINE_PARSER_METHOD(tblref) { return 1; } /* exc attr */ static EIMIL_symbol* PCE_attr_get_property_symbol( EIMIL_data *ped, PCE_parse_context *pcx, EIMIL_attrs *patr ) { for (; patr->name;patr++) { if (strcmp(patr->name, "p") == 0) { EIMIL_symbol *psym; UTF8 *name; if (!EIMIL_get_attr_nmtokens(patr->val, &name)) { EIMIL_set_error_pt(ped, NULL, "Unrecogized keyword in `p'"); return NULL; } psym = PCE_get_property(ped, pcx, name); return psym; } } return NULL; } DEFINE_PARSER_METHOD(makeprop) { if (type != EIMIL_EMPTY_TAG) return 0; { PCE_parse_context *pcx = (PCE_parse_context*) *pprivate; EIMIL_symbol *psym; PCE_code *pc, *pc_arg; psym = PCE_attr_get_property_symbol(ped, pcx, patr); pc_arg = PCE_new_code_for_symbol(pcx->psym); if (!pc_arg) { PCE_set_error(ped, PCE_MEMORY_ERROR); return 0; } pc = PCE_new_code_for_inst(PCE_makeprop_exec); if (!pc) { PCE_set_error(ped, PCE_MEMORY_ERROR); return 0; } pc->parg = pc_arg; PCE_ADD_CODE(pcx, pc); } return 1; } DEFINE_PARSER_METHOD(getmprop) { PCE_parse_context *pcx = (PCE_parse_context*) *pprivate; switch (type) { case EIMIL_START_TAG: { EIMIL_symbol *psym; psym = PCE_attr_get_property_symbol(ped, pcx, patr); pcx = PCE_parser_generic_start(ped, pcx, EIMIL_TYPE_NONE); if (!pcx) return 0; pcx->required_type[0] = EIMIL_TYPE_MTEXT; pcx->required_type[1] = EIMIL_TYPE_NUMBER; pcx->mode = PCE_NEW_PARSER_CONTEXT_MODE(pcx, 0); pcx->psym = psym; *pprivate = pcx; return 1; } case EIMIL_CHARDATA: if (PCE_parse_token(ped, pcx, pchars) == PCE_SUCCESS) return 1; return 0; case EIMIL_END_TAG: { PCE_code *pc = PCE_new_code_for_symbol(pcx->psym); if (!pc) { PCE_set_error(ped, PCE_MEMORY_ERROR); return 0; } pcx = PCE_parser_generic_end(ped, pcx, PCE_new_code_for_inst(PCE_getmprop_exec)); /* Insert EIMIL_exception symbol to the first argument of `catch'. */ pc->pnext = pcx->pc->parg; pcx->pc->parg = pc; if (!pcx) return 0; return 1; } default: break; } return 0; } DEFINE_PARSER_METHOD(findmprop) { PCE_parse_context *pcx = (PCE_parse_context*) *pprivate; switch (type) { case EIMIL_START_TAG: { EIMIL_symbol *psym; psym = PCE_attr_get_property_symbol(ped, pcx, patr); pcx = PCE_parser_generic_start(ped, pcx, EIMIL_TYPE_NONE); if (!pcx) return 0; pcx->required_type[0] = EIMIL_TYPE_MTEXT; pcx->required_type[1] = EIMIL_TYPE_NUMBER; pcx->mode = PCE_NEW_PARSER_CONTEXT_MODE(pcx, 0); pcx->psym = psym; *pprivate = pcx; return 1; } case EIMIL_CHARDATA: if (PCE_parse_token(ped, pcx, pchars) == PCE_SUCCESS) return 1; return 0; case EIMIL_END_TAG: { PCE_code *pc = PCE_new_code_for_symbol(pcx->psym); if (!pc) { PCE_set_error(ped, PCE_MEMORY_ERROR); return 0; } pcx = PCE_parser_generic_end(ped, pcx, PCE_new_code_for_inst(PCE_findmprop_exec)); /* Insert EIMIL_exception symbol to the first argument of `catch'. */ pc->pnext = pcx->pc->parg; pcx->pc->parg = pc; if (!pcx) return 0; return 1; } default: break; } return 0; } DEFINE_PARSER_METHOD(interact) { return 1; } DEFINE_PARSER_METHOD(match) { return 1; } DEFINE_PARSER_METHOD(forward) { return 1; } DEFINE_PARSER_METHOD(send) { return 1; } /* v attr */ static EIMIL_symbol* PCE_attr_get_variable_symbol( EIMIL_data *ped, PCE_parse_context *pcx, EIMIL_attrs *patr ) { for (; patr->name;patr++) { if (strcmp(patr->name, "v") == 0) { EIMIL_symbol *psym; UTF8 *name; if (!EIMIL_get_attr_nmtokens(patr->val, &name)) { EIMIL_set_error_pt(ped, NULL, "Unrecogized keyword in `v'"); return NULL; } psym = PCE_get_variable(ped, pcx, name); free(name); if (!psym) return NULL; return psym; } } return NULL; } DEFINE_PARSER_METHOD(set) { PCE_parse_context *pcx = (PCE_parse_context*) *pprivate; switch (type) { case EIMIL_START_TAG: { EIMIL_symbol *psym; psym = PCE_attr_get_variable_symbol(ped, pcx, patr); if (!psym) { EIMIL_set_error_pt(ped, NULL, "invalid `v' attribute in `set' element."); return 0; } pcx = PCE_parser_generic_start(ped, pcx, psym->obj.v.type); if (!pcx) return 0; pcx->required_type[0] = psym->obj.v.type | EIMIL_TYPE_NIL; pcx->mode = PCE_NEW_PARSER_CONTEXT_MODE(pcx, 0); pcx->psym = psym; *pprivate = pcx; return 1; } case EIMIL_CHARDATA: if (PCE_parse_token(ped, pcx, pchars) == PCE_SUCCESS) return 1; return 0; case EIMIL_END_TAG: { PCE_code *pc = PCE_new_code_for_symbol(pcx->psym); if (!pc) { PCE_set_error(ped, PCE_MEMORY_ERROR); return 0; } PCE_ADD_CODE(pcx, pc); pcx = PCE_parser_generic_end(ped, pcx, PCE_new_code_for_inst(PCE_set_exec)); if (!pcx) return 0; return 1; } default: break; } return 0; } /* f attr */ static EIMIL_symbol* PCE_attr_get_function_symbol( EIMIL_data *ped, PCE_parse_context *pcx, EIMIL_attrs *patr ) { for (; patr->name;patr++) { if (strcmp(patr->name, "f") == 0) { EIMIL_symbol *psym; UTF8 *name; if (!EIMIL_get_attr_nmtokens(patr->val, &name)) { EIMIL_set_error_pt(ped, NULL, "Unrecogized keyword in `v'"); return NULL; } psym = PCE_get_function(ped, pcx, name); free(name); if (!psym) return NULL; return psym; } } return NULL; } DEFINE_PARSER_METHOD(e) { PCE_parse_context *pcx = (PCE_parse_context*) *pprivate; switch (type) { case EIMIL_START_TAG: { EIMIL_symbol *psym; PCE_function *pf; psym = PCE_attr_get_function_symbol(ped, pcx, patr); pf = (PCE_function*) psym->obj.f.def; pcx = PCE_parser_generic_start(ped, pcx, pf->rettype); if (!pcx) return 0; pcx->mode = PCE_NEW_PARSER_CONTEXT_MODE(pcx, PCE_IN_E); pcx->pf = pf; *pprivate = pcx; return 1; } case EIMIL_CHARDATA: if (PCE_parse_token(ped, pcx, pchars) == PCE_SUCCESS) return 1; return 0; case EIMIL_END_TAG: pcx = PCE_parser_generic_end(ped, pcx, PCE_new_code_for_function(pcx->pf)); if (!pcx) return 0; return 1; default: break; } return 0; } /* PCE root element */ DEFINE_PARSER_METHOD(PCE) { PCE_parse_context *pcx; if (type == EIMIL_START_TAG) { PCE_context *pctx = (PCE_context*) *pprivate; pcx = PCE_new_parse_context(ped); if (!pcx) return 0; if (PCE_initialize_labels(pcx) != PCE_SUCCESS) return 0; pcx->pctx = pctx; pcx->required_type[0] = EIMIL_TYPE_ANY | EIMIL_TYPE_OPTION1; *pprivate = pcx; return 1; } else { pcx = (PCE_parse_context*) *pprivate; ASSERT(!pcx->pnext); PCE_finalize_labels(ped, pcx); /* Almost all of the work on pcx->pctx should be done in the subelement parsers. Thus currently do nothing in the root parser. */ free(pcx); return 1; } return 0; } /**************************************** factory method ****************************************/ static void PCE_SEH_free( PCE_SEH_block *pseh ); static void PCE_destruct_context( PCE_context *pctx ) { EIMIL_free_dictionary(pctx->pdic); { PCE_SEH_block *pseh1, *pseh2; for (pseh1 = pctx->pseh; pseh1; ) { pseh2 = pseh1->pnext; PCE_SEH_free(pseh1); pseh1 = pseh2; } } free(pctx); } static void PCE_destruct_data( PCE_data *pd ) { PCE_free_code(pd->pcode); free(pd); } static void* PCE_handler( enum EIMIL_ENGINE_COMMAND m, EIMIL_data *ped, void *class_private, void *handle_private ) { PCE_data *pd = (PCE_data*) class_private; PCE_context *ph = (PCE_context*) handle_private; switch (m) { case EIMIL_ENGINE_INSTANCIATE: pd = (PCE_data*) malloc(sizeof(PCE_data)); if (!pd) return NULL; memset(pd, 0, sizeof(*pd)); return pd; case EIMIL_ENGINE_DUPLICATE: if (!ph) { ph = (PCE_context*) malloc(sizeof(PCE_context)); if (!ph) return NULL; memset(ph, 0, sizeof(PCE_context)); ph->ped = ped; PCE_new_dictionary(ped, ph); ph->ppce_data = pd; if (!ph->pdic) { free(ph); return NULL; } return ph; } else { PCE_context *pnh; pnh = (PCE_context*) malloc(sizeof(PCE_context)); if (!pnh) return NULL; memset(pnh, 0, sizeof(PCE_context)); pnh->ped = ped; pnh->pdic = EIMIL_duplicate_dictionary(ph->pdic); pnh->ppce_data = ph->ppce_data; if (!pnh->pdic) { free(pnh); return NULL; } return pnh; } case EIMIL_ENGINE_DESTRUCT: PCE_destruct_context(ph); return NULL; case EIMIL_ENGINE_UNINSTANCIATE: PCE_destruct_data(pd); return NULL; } return NULL; } /******************************************************************************** PCE execution part *********************************************************************************/ /**************************************** SEH ****************************************/ static enum PCE_ERROR_CODE PCE_SEH_start( PCE_context *pctx ) { PCE_SEH_block* pseh = (PCE_SEH_block*) malloc(sizeof(PCE_SEH_block)); if (!pseh) return PCE_MEMORY_ERROR; memset(pseh, 0, sizeof(PCE_SEH_block)); pseh->pnext = pctx->pseh; pctx->pseh = pseh; return PCE_SUCCESS; } static void PCE_SEH_free( PCE_SEH_block *pseh ) { PCE_SEH_catchblock *pc1, *pc2; for (pc1 = pseh->pcatchers; pc1; ) { pc2 = pc1->pnext; free(pc1); pc1 = pc2; } free(pseh); } static enum PCE_ERROR_CODE PCE_SEH_catch( PCE_context *pctx, enum PCE_ERROR_CODE e, PCE_SEH_CATCH_FUNCTION f, void *arg ) { PCE_SEH_catchblock *pc; PCE_SEH_block *pseh = pctx->pseh; pc = (PCE_SEH_catchblock*) malloc(sizeof(PCE_SEH_catchblock)); if (!pc) return PCE_MEMORY_ERROR; pc->pnext = pseh->pcatchers; pc->type = e; pc->pcfs = f; pc->catcharg = arg; pseh->pcatchers = pc; return PCE_SUCCESS; } static enum PCE_ERROR_CODE PCE_SEH_try( PCE_context *pctx, PCE_SEH_TRY_FUNCTION tf, void *arg ) { int ecode; enum PCE_ERROR_CODE r; PCE_SEH_block *pseh = pctx->pseh; if ((ecode = setjmp(pseh->jmp)) != 0) { PCE_SEH_catchblock *pcb; PCE_SEH_block *psehh1, *psehh2; for (psehh1 = pctx->pseh; psehh1 != pseh; ) { psehh2 = psehh1->pnext; PCE_SEH_free(psehh1); psehh1 = psehh2; } for (pcb = pseh->pcatchers; pcb; pcb = pcb->pnext) { if ((pcb->type == PCE_ANY_ERROR) || (ecode == pcb->type)) { void *throwarg = pseh->arg; void *catcharg = pcb->catcharg; PCE_SEH_CATCH_FUNCTION pcfs = pcb->pcfs; pctx->pseh = pseh->pnext; PCE_SEH_free(pseh); r = (*pcfs)(pctx, ecode, throwarg, catcharg); return r; } } /* fail to find out any handlers, thus propagate the exception. */ if (!pseh->pnext) abort(); pseh->pnext->arg = pseh->arg; pctx->pseh = pseh->pnext; PCE_SEH_free(pseh); longjmp(pctx->pseh->jmp, ecode); } else { r = (*tf)(pctx, arg); } pctx->pseh = pseh->pnext; PCE_SEH_free(pseh); return r; } static void PCE_SEH_throw( PCE_context *pctx, int ecode, void *arg ) { PCE_SEH_block *pseh = pctx->pseh; pseh->arg = arg; longjmp(pseh->jmp, ecode); } /**************************************** Expression Evaluation ****************************************/ static EIMIL_value* PCE_call( PCE_context *pctx, PCE_function *pf, PCE_code *parg ); static EIMIL_value* PCE_eval( PCE_context *pctx, PCE_code *pc ) { EIMIL_value *pv; for (;;) { if (!pc) break; switch (pc->type) { case PCE_CODE_VALUE: pv = pc->val.pv; pctx->pcur = pc->pnext; return pv; case PCE_CODE_SYMBOL: pv = PCE_symbol_value(pctx, pc); pctx->pcur = pc->pnext; return pv; case PCE_CODE_JMP: pc = pctx->pcur = pc->val.pc_to; continue; case PCE_CODE_COND_JMP: pv = PCE_eval(pctx, pc->parg); if (pv) { EIMIL_REFCHECK(*pv); pc = pctx->pcur = pc->val.pc_to; } else { pc = pctx->pcur = pc->pnext; } continue; case PCE_CODE_COND_NOT_JMP: pv = PCE_eval(pctx, pc->parg); if (pv) { EIMIL_REFCHECK(*pv); pc = pctx->pcur = pc->pnext; } else { pc = pctx->pcur = pc->val.pc_to; } continue; case PCE_CODE_FUNCTION: pv = PCE_call(pctx, pc->val.pf, pc->parg); pctx->pcur = pc->pnext; return pv; default: ASSERT(pc->type == PCE_CODE_INST); pctx->pcur = pc; pv = (*pc->val.h)(pctx); pctx->pcur = pc->pnext; return pv; } } return NULL; } enum PCE_ERROR_CODE PCE_execute_loop( PCE_context *pctx, void *arg ) { PCE_code *pc; EIMIL_value *pv; if (!pctx->pcur) { pc = pctx->ppce_data->pcode; ASSERT(pc->type == PCE_CODE_MAIN); pc = pc->parg; pctx->pcur = pc; } for (;;){ pc = pctx->pcur; if (!pc) break; pv = PCE_eval(pctx, pc); if (pv) EIMIL_REFCHECK(*pv); } return PCE_SUCCESS; } static void PCE_bind_function_arg( PCE_context *pctx, PCE_function *pf, PCE_code *parg ) { int i; PCE_funcproto *pfp; EIMIL_value *pv; int idx = pctx->depth++; pctx->pfuncdic[idx] = pf->pdic; for (i = 0, pfp = pf->pfp; i < pf->nargs; i++, pfp++) { ASSERT(parg); pv = PCE_eval(pctx, parg); pfp->psym->obj.v.pv = pv; if (pv) EIMIL_ADDREF(*pv); parg = parg->pnext; } pctx->pdic_f = pf->pdic; return; } static void PCE_unbind_function_arg( PCE_context *pctx, PCE_function *pf ) { int i; PCE_funcproto *pfp; EIMIL_value *pv; int idx = --pctx->depth; if (idx == 0) pctx->pdic_f = NULL; else pctx->pdic_f = pctx->pfuncdic[idx - 1]; for (i = 0, pfp = pf->pfp; i < pf->nargs; i++, pfp++) { pv = pfp->psym->obj.v.pv; if (pv) EIMIL_RMREF(*pv); } return; } struct PCE_call_catcharg { EIMIL_value *pv; PCE_function *pf; }; static enum PCE_ERROR_CODE PCE_call_exception_handler( PCE_context *pctx, int ecode, void *throwarg, void *catcharg ) { struct PCE_call_catcharg *pcarg = (struct PCE_call_catcharg*) catcharg; if (ecode == PCE_RETURN_JMP_ERROR) { pcarg->pv = (EIMIL_value*) throwarg; } else { PCE_unbind_function_arg(pctx, pcarg->pf); PCE_SEH_throw(pctx, ecode, throwarg); } return PCE_SUCCESS; } static EIMIL_value* PCE_call( PCE_context *pctx, PCE_function *pf, PCE_code *parg ) { enum PCE_ERROR_CODE r; struct PCE_call_catcharg carg; if (pctx->depth >= PCE_CALL_MAX_DEPTH) { PCE_SEH_throw(pctx, PCE_OVER_EVAL_DEPTH_ERROR, NULL); } if (PCE_SEH_start(pctx) != PCE_SUCCESS) return NULL; PCE_bind_function_arg(pctx, pf, parg); carg.pv = NULL; carg.pf = pf; if (PCE_SEH_catch(pctx, PCE_ANY_ERROR, PCE_call_exception_handler, &carg) != PCE_SUCCESS) return NULL; pctx->pcur = pf->pc; r = PCE_SEH_try(pctx, PCE_execute_loop, NULL); PCE_unbind_function_arg(pctx, pf); if (r == PCE_SUCCESS) return carg.pv; return NULL; } /* Retrieve the argument of current instruction. Return code: PCE_SUCCESS --> Successfully retrieve the value of argument. PCE_NO_MORE_ARG_ERROR --> There is no arg of idx. Exception: PCE_WRONG_TYPE_ARGUMENT_ERROR */ static enum PCE_ERROR_CODE PCE_get_arg( PCE_context *pctx, int idx, int type, EIMIL_value** ppv ) { int i; EIMIL_value *pv; PCE_code *pc_orig, *pc; pc_orig = pctx->pcur; pc = pc_orig->parg; for (i = 0; i < idx; i++) { if (!pc) break; pc = pc->pnext; } if (!pc) return PCE_NO_MORE_ARG_ERROR; pv = PCE_eval(pctx, pc); pctx->pcur = pc_orig; if ((type & EIMIL_TYPE_ANY) || (!pv && (type & EIMIL_TYPE_NIL)) || (pv && ((pv->type & type) != 0))) { *ppv = pv; return PCE_SUCCESS; } PCE_SEH_throw(pctx, PCE_WRONG_TYPE_ARGUMENT_ERROR, NULL); return PCE_UNKNOWN_ERROR; } static EIMIL_symbol* PCE_get_symbol_arg( PCE_context *pctx, int idx, enum EIMIL_CATEGORY cat ) { int i; EIMIL_symbol *psym; PCE_code *pc = pctx->pcur; pc = pc->parg; for (i = 0; i < idx; i++) { if (!pc) { ERROR_INTERNAL("!!Invalid PCE_code(Too few args)."); } pc = pc->pnext; } ASSERT(pc->type == PCE_CODE_SYMBOL); psym = PCE_lookup_symbol(pctx, pc); ASSERT(psym); ASSERT(psym->cat == cat); return psym; } static enum PCE_ERROR_CODE PCE_get_arg_or_error( PCE_context *pctx, int idx, int type, EIMIL_value** ppv ) { enum PCE_ERROR_CODE r = PCE_get_arg(pctx, idx, type, ppv); if (r == PCE_NO_MORE_ARG_ERROR) { PCE_SEH_throw(pctx, PCE_TOO_FEW_ARGUMENTS_ERROR, NULL); } else if (r != PCE_SUCCESS) { PCE_SEH_throw(pctx, PCE_UNKNOWN_ERROR, NULL); } return r; } static int PCE_get_arg_totnum( PCE_context *pctx ) { int i; PCE_code *pc = pctx->pcur; for (i = 0, pc = pc->parg; pc; i++, pc = pc->pnext); return i; } /**************************************** Predefined variables. ****************************************/ static void PCE_set_current_event( PCE_context *pctx, EIMIL_value *pv_event ) { EIMIL_symbol *psym = pctx->psym_cev; psym->obj.v.pv = pv_event; EIMIL_ADDREF(*pv_event); return; } /**************************************** Execution methods. ****************************************/ DEFINE_EXEC_METHOD(undo) { /* TODO */ return NULL; } DEFINE_EXEC_METHOD(mark_undo) { /* TODO */ return NULL; } DEFINE_EXEC_METHOD(try) { /* TODO */ return NULL; } DEFINE_EXEC_METHOD(catch) { /* TODO */ return NULL; } DEFINE_EXEC_METHOD(throw) { /* TODO */ return NULL; } DEFINE_EXEC_METHOD(keycase) { /* TODO */ return NULL; } DEFINE_EXEC_METHOD(keymap) { /* TODO */ return NULL; } DEFINE_EXEC_METHOD(toggle_preedit) { /* TODO */ return NULL; } DEFINE_EXEC_METHOD(toggle_lookup_choice) { /* TODO */ return NULL; } DEFINE_EXEC_METHOD(keyeventp) { EIMIL_value *pv; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_EVENT, &pv); if (strcmp(pv->v.event.type, "key") == 0) return EIMIL_construct_bool(1); return NULL; } DEFINE_EXEC_METHOD(or) { int i; EIMIL_value *pv; for (i = 0; ; i++) { if (PCE_get_arg(pctx, i, EIMIL_TYPE_ANY, &pv) == PCE_NO_MORE_ARG_ERROR) break; if (pv) return EIMIL_construct_bool(1); } return NULL; } DEFINE_EXEC_METHOD(and) { int i; EIMIL_value *pv; for (i = 0; ; i++) { if (PCE_get_arg(pctx, i, EIMIL_TYPE_ANY, &pv) == PCE_NO_MORE_ARG_ERROR) break; if (!pv) return NULL; } return EIMIL_construct_bool(1); } DEFINE_EXEC_METHOD(not) { EIMIL_value *pv; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_ANY, &pv); if (pv) { EIMIL_REFCHECK(*pv); return NULL; } return EIMIL_construct_bool(1); } DEFINE_EXEC_METHOD(gt) { EIMIL_value *pv1, *pv2, *pvr; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_NUMBER, &pv1); PCE_get_arg_or_error(pctx, 1, EIMIL_TYPE_NUMBER, &pv2); if (pv1->v.number > pv2->v.number) pvr = EIMIL_construct_bool(1); else pvr = NULL; EIMIL_REFCHECK(*pv1); EIMIL_REFCHECK(*pv2); return pvr; } DEFINE_EXEC_METHOD(lt) { EIMIL_value *pv1, *pv2, *pvr; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_NUMBER, &pv1); PCE_get_arg_or_error(pctx, 1, EIMIL_TYPE_NUMBER, &pv2); if (pv1->v.number < pv2->v.number) pvr = EIMIL_construct_bool(1); else pvr = NULL; EIMIL_REFCHECK(*pv1); EIMIL_REFCHECK(*pv2); return pvr; } DEFINE_EXEC_METHOD(le) { EIMIL_value *pv1, *pv2, *pvr; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_NUMBER, &pv1); PCE_get_arg_or_error(pctx, 1, EIMIL_TYPE_NUMBER, &pv2); if (pv1->v.number <= pv2->v.number) pvr = EIMIL_construct_bool(1); else pvr = NULL; EIMIL_REFCHECK(*pv1); EIMIL_REFCHECK(*pv2); return pvr; } DEFINE_EXEC_METHOD(ge) { EIMIL_value *pv1, *pv2, *pvr; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_NUMBER, &pv1); PCE_get_arg_or_error(pctx, 1, EIMIL_TYPE_NUMBER, &pv2); if (pv1->v.number >= pv2->v.number) pvr = EIMIL_construct_bool(1); else pvr = NULL; EIMIL_REFCHECK(*pv1); EIMIL_REFCHECK(*pv2); return pvr; } DEFINE_EXEC_METHOD(eql) { EIMIL_value *pv1, *pv2, *pvr; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_NUMBER, &pv1); PCE_get_arg_or_error(pctx, 1, EIMIL_TYPE_NUMBER, &pv2); if (pv1->v.number == pv2->v.number) pvr = EIMIL_construct_bool(1); else pvr = NULL; EIMIL_REFCHECK(*pv1); EIMIL_REFCHECK(*pv2); return pvr; } DEFINE_EXEC_METHOD(propval) { int idx; EIMIL_value *pv_prop, *pv_idx, *pvr; EIMIL_prop *pprop; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_PROP, &pv_prop); PCE_get_arg_or_error(pctx, 1, EIMIL_TYPE_NUMBER, &pv_idx); pprop = &pv_prop->v.prop; idx = pv_idx->v.number; EIMIL_REFCHECK(*pv_idx); if ((idx < 0) || (pprop->size <= idx)) { EIMIL_REFCHECK(*pv_prop); return NULL; } pvr = pprop->pvals[idx]; EIMIL_REFCHECK_GUARD(*pv_prop, *pvr); return pvr; } DEFINE_EXEC_METHOD(propsize) { EIMIL_value *pv_prop; EIMIL_prop *pprop; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_PROP, &pv_prop); pprop = &pv_prop->v.prop; return EIMIL_construct_number(pprop->size); } DEFINE_EXEC_METHOD(propmbeg) { EIMIL_value *pv_prop; EIMIL_prop *pprop; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_PROP, &pv_prop); pprop = &pv_prop->v.prop; return EIMIL_construct_number(pprop->st); } DEFINE_EXEC_METHOD(propmend) { EIMIL_value *pv_prop; EIMIL_prop *pprop; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_PROP, &pv_prop); pprop = &pv_prop->v.prop; return EIMIL_construct_number(pprop->end); } DEFINE_EXEC_METHOD(evval) { EIMIL_value *pv, *pvr; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_EVENT, &pv); pvr = pv->v.event.pv_val; EIMIL_REFCHECK_GUARD(*pv, *pvr); return pvr; } DEFINE_EXEC_METHOD(evmod) { EIMIL_value *pv, *pvr; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_EVENT, &pv); pvr = pv->v.event.pv_mod; EIMIL_REFCHECK_GUARD(*pv, *pvr); return pvr; } DEFINE_EXEC_METHOD(strlen) { int len; EIMIL_value *pv_mtext; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_MTEXT, &pv_mtext); len = pv_mtext->v.mtext.len; EIMIL_REFCHECK(*pv_mtext); return EIMIL_construct_number(len); } DEFINE_EXEC_METHOD(strcmp) { int r; EIMIL_value *pv_mtext1, *pv_mtext2; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_MTEXT, &pv_mtext1); PCE_get_arg_or_error(pctx, 1, EIMIL_TYPE_MTEXT, &pv_mtext2); r = EIMIL_UTF32_strcmp(pv_mtext1->v.mtext.ustr, pv_mtext2->v.mtext.ustr); EIMIL_REFCHECK(*pv_mtext1); EIMIL_REFCHECK(*pv_mtext2); return EIMIL_construct_number(r); } DEFINE_EXEC_METHOD(add) { int i, n; EIMIL_value *pv; n = 0; for (i = 0; ; i++) { if (PCE_get_arg(pctx, i, EIMIL_TYPE_NUMBER, &pv) == PCE_NO_MORE_ARG_ERROR) break; n += pv->v.number; EIMIL_REFCHECK(*pv); } pv = EIMIL_construct_number(n); if (!pv) PCE_SEH_throw(pctx, PCE_MEMORY_ERROR, NULL); return pv; } DEFINE_EXEC_METHOD(sub) { int i, n; EIMIL_value *pv; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_NUMBER, &pv); n = pv->v.number; EIMIL_REFCHECK(*pv); for (i = 1; ; i++) { if (PCE_get_arg(pctx, i, EIMIL_TYPE_NUMBER, &pv) == PCE_NO_MORE_ARG_ERROR) break; n -= pv->v.number; EIMIL_REFCHECK(*pv); } pv = EIMIL_construct_number(n); if (!pv) PCE_SEH_throw(pctx, PCE_MEMORY_ERROR, NULL); return pv; } DEFINE_EXEC_METHOD(mul) { int i, n; EIMIL_value *pv; n = 1; for (i = 0; ; i++) { if (PCE_get_arg(pctx, i, EIMIL_TYPE_NUMBER, &pv) == PCE_NO_MORE_ARG_ERROR) break; n *= pv->v.number; EIMIL_REFCHECK(*pv); } pv = EIMIL_construct_number(n); if (!pv) PCE_SEH_throw(pctx, PCE_MEMORY_ERROR, NULL); return pv; } DEFINE_EXEC_METHOD(div) { int i, n; EIMIL_value *pv; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_NUMBER, &pv); n = pv->v.number; EIMIL_REFCHECK(*pv); for (i = 1; ; i++) { if (PCE_get_arg(pctx, i, EIMIL_TYPE_NUMBER, &pv) == PCE_NO_MORE_ARG_ERROR) break; n /= pv->v.number; EIMIL_REFCHECK(*pv); } pv = EIMIL_construct_number(n); if (!pv) PCE_SEH_throw(pctx, PCE_MEMORY_ERROR, NULL); return pv; } DEFINE_EXEC_METHOD(mod) { int i, n; EIMIL_value *pv; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_NUMBER, &pv); n = pv->v.number; EIMIL_REFCHECK(*pv); for (i = 1; ; i++) { if (PCE_get_arg(pctx, i, EIMIL_TYPE_NUMBER, &pv) == PCE_NO_MORE_ARG_ERROR) break; n %= pv->v.number; EIMIL_REFCHECK(*pv); } pv = EIMIL_construct_number(n); if (!pv) PCE_SEH_throw(pctx, PCE_MEMORY_ERROR, NULL); return pv; } DEFINE_EXEC_METHOD(bor) { int i, n; EIMIL_value *pv; if (PCE_get_arg(pctx, 0, EIMIL_TYPE_NUMBER, &pv) == PCE_NO_MORE_ARG_ERROR) { PCE_SEH_throw(pctx, PCE_TOO_FEW_ARGUMENTS_ERROR, NULL); } n = pv->v.number; EIMIL_REFCHECK(*pv); for (i = 1; ; i++) { if (PCE_get_arg(pctx, i, EIMIL_TYPE_NUMBER, &pv) == PCE_NO_MORE_ARG_ERROR) break; n |= pv->v.number; EIMIL_REFCHECK(*pv); } pv = EIMIL_construct_number(n); if (!pv) PCE_SEH_throw(pctx, PCE_MEMORY_ERROR, NULL); return pv; } DEFINE_EXEC_METHOD(band) { int i, n; EIMIL_value *pv; if (PCE_get_arg(pctx, 0, EIMIL_TYPE_NUMBER, &pv) == PCE_NO_MORE_ARG_ERROR) { PCE_SEH_throw(pctx, PCE_TOO_FEW_ARGUMENTS_ERROR, NULL); } n = pv->v.number; EIMIL_REFCHECK(*pv); for (i = 1; ; i++) { if (PCE_get_arg(pctx, i, EIMIL_TYPE_NUMBER, &pv) == PCE_NO_MORE_ARG_ERROR) break; n &= pv->v.number; EIMIL_REFCHECK(*pv); } pv = EIMIL_construct_number(n); if (!pv) PCE_SEH_throw(pctx, PCE_MEMORY_ERROR, NULL); return pv; } DEFINE_EXEC_METHOD(bxor) { int i, n; EIMIL_value *pv; if (PCE_get_arg(pctx, 0, EIMIL_TYPE_NUMBER, &pv) == PCE_NO_MORE_ARG_ERROR) { PCE_SEH_throw(pctx, PCE_TOO_FEW_ARGUMENTS_ERROR, NULL); } n = pv->v.number; EIMIL_REFCHECK(*pv); for (i = 1; ; i++) { if (PCE_get_arg(pctx, i, EIMIL_TYPE_NUMBER, &pv) == PCE_NO_MORE_ARG_ERROR) break; n ^= pv->v.number; EIMIL_REFCHECK(*pv); } pv = EIMIL_construct_number(n); if (!pv) PCE_SEH_throw(pctx, PCE_MEMORY_ERROR, NULL); return pv; } DEFINE_EXEC_METHOD(UCSval) { UTF32 ch; EIMIL_value *pv; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_CHAR, &pv); ch = pv->v.ch; EIMIL_REFCHECK(*pv); return EIMIL_construct_number((int)ch); } DEFINE_EXEC_METHOD(propadd) { EIMIL_value *pv_prop, *pv_val; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_PROP, &pv_prop); PCE_get_arg_or_error(pctx, 1, pv_prop->v.prop.type, &pv_val); if (!EIMIL_add_prop(&pv_prop->v.prop, pv_val)) { PCE_SEH_throw(pctx, PCE_MEMORY_ERROR, NULL); } EIMIL_ADDREF(*pv_val); return pv_prop; } DEFINE_EXEC_METHOD(propcopy) { EIMIL_value *pv_prop, *pv_prop2; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_PROP, &pv_prop); pv_prop2 = EIMIL_copy_value(pv_prop); if (!pv_prop2) { PCE_SEH_throw(pctx, PCE_MEMORY_ERROR, NULL); } return pv_prop2; } DEFINE_EXEC_METHOD(evchar) { EIMIL_value *pv; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_EVENT, &pv); return pv->v.event.pv_char; } DEFINE_EXEC_METHOD(strref) { int idx, len; UTF32* pstr, ch; EIMIL_value *pv_mtext, *pv_idx; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_MTEXT, &pv_mtext); PCE_get_arg_or_error(pctx, 1, EIMIL_TYPE_NUMBER, &pv_idx); pstr = pv_mtext->v.mtext.ustr; len = pv_mtext->v.mtext.len; idx = pv_idx->v.number; if ((idx < 0) || (idx >= len)) { PCE_SEH_throw(pctx, PCE_OUT_OF_RANGE_ERROR, NULL); } ch = pstr[idx]; EIMIL_REFCHECK(*pv_mtext); EIMIL_REFCHECK(*pv_idx); return EIMIL_construct_char(ch); } DEFINE_EXEC_METHOD(makechar) { int n; EIMIL_value *pv; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_NUMBER, &pv); n = pv->v.number; EIMIL_REFCHECK(*pv); return EIMIL_construct_char((UTF32)n); } DEFINE_EXEC_METHOD(evtype) { EIMIL_value *pv; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_EVENT, &pv); return EIMIL_construct_mtext_from_UTF8(pv->v.event.type); } DEFINE_EXEC_METHOD(evmtext) { EIMIL_value *pv, *pvr; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_EVENT, &pv); pvr = pv->v.event.pv_mtext; EIMIL_REFCHECK_GUARD(*pv, *pvr); return pvr; } DEFINE_EXEC_METHOD(concat) { int i, n; EIMIL_value *pvr; EIMIL_value **ppv; n = PCE_get_arg_totnum(pctx); if (n == 0) return EIMIL_construct_mtext_from_UTF8(""); #if 1 ppv = (EIMIL_value**) alloca(sizeof(EIMIL_value*) * n); #else ppv = (EIMIL_value**) malloc(sizeof(EIMIL_value*) * n); #endif for (i = 0; i < n; i++) { PCE_get_arg_or_error(pctx, i, EIMIL_TYPE_CHAR | EIMIL_TYPE_MTEXT, ppv + i); } pvr = EIMIL_mtext_concat(n, ppv); for (i = 0; i < n; i++) { EIMIL_REFCHECK(*(ppv[i])); } #if 1 #else free(ppv); #endif return pvr; } DEFINE_EXEC_METHOD(substr) { int beg, end, len; EIMIL_value *pv_mtext, *pv_beg, *pv_end, *pvr; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_MTEXT, &pv_mtext); len = pv_mtext->v.mtext.len; PCE_get_arg_or_error(pctx, 1, EIMIL_TYPE_NUMBER, &pv_beg); beg = pv_beg->v.number; EIMIL_REFCHECK(*pv_beg); if (PCE_get_arg(pctx, 2, EIMIL_TYPE_NUMBER, &pv_end) == PCE_NO_MORE_ARG_ERROR) { end = len; } else { end = pv_end->v.number; EIMIL_REFCHECK(*pv_end); } if ((beg < 0) || (beg >= end) || (end > len)) { PCE_SEH_throw(pctx, PCE_OUT_OF_RANGE_ERROR, NULL); } pvr = EIMIL_mtext_substr(pv_mtext, beg, end); EIMIL_REFCHECK(*pv_mtext); return pvr; } DEFINE_EXEC_METHOD(next) { EIMIL_value *pv_event; if (PCE_get_arg(pctx, 0, EIMIL_TYPE_ANY, &pv_event) == PCE_SUCCESS) { EIMIL_reply_event(pctx->ped, pv_event); } EIMIL_REFCHECK(*pv_event); pv_event = EIMIL_next_event(pctx->ped); if (pv_event) { PCE_set_current_event(pctx, pv_event); } else { PCE_SEH_throw(pctx, PCE_WAIT_NEXT_EVENT_ERROR, NULL); } return NULL; } DEFINE_EXEC_METHOD(makeev) { UTF8* type; EIMIL_value *pv_type, *pv_val, *pv_mod, *pv_char, *pv_mtext; EIMIL_value *ret; pv_val = pv_char = pv_mtext = NULL; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_MTEXT, &pv_type); type = EIMIL_convert_UTF32_to_UTF8(pv_type->v.mtext.ustr); if (!type) { PCE_SEH_throw(pctx, PCE_MEMORY_ERROR, NULL); } PCE_get_arg_or_error(pctx, 1, EIMIL_TYPE_NUMBER | EIMIL_TYPE_NIL, &pv_val); PCE_get_arg_or_error(pctx, 2, EIMIL_TYPE_NUMBER | EIMIL_TYPE_NIL, &pv_mod); PCE_get_arg_or_error(pctx, 3, EIMIL_TYPE_CHAR | EIMIL_TYPE_NIL, &pv_char); PCE_get_arg_or_error(pctx, 4, EIMIL_TYPE_MTEXT | EIMIL_TYPE_NIL, &pv_mtext); ret = EIMIL_construct_event(type, pv_val, pv_mod, pv_char, pv_mtext); if (type) free(type); return ret; } DEFINE_EXEC_METHOD(commit) { return NULL; } DEFINE_EXEC_METHOD(unroll) { return NULL; } DEFINE_EXEC_METHOD(propdel) { int idx; EIMIL_value *pv_prop, *pv_idx; EIMIL_prop *pprop; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_PROP, &pv_prop); PCE_get_arg_or_error(pctx, 1, EIMIL_TYPE_NUMBER, &pv_idx); pprop = &pv_prop->v.prop; idx = pv_idx->v.number; EIMIL_delete_prop(pprop, idx); EIMIL_REFCHECK(*pv_prop); EIMIL_REFCHECK(*pv_idx); return NULL; } DEFINE_EXEC_METHOD(addmprop) { int beg, end, len; EIMIL_value *pv_target, *pv_prop, *pv_beg, *pv_end; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_MTEXT, &pv_target); PCE_get_arg_or_error(pctx, 1, EIMIL_TYPE_PROP, &pv_prop); PCE_get_arg_or_error(pctx, 2, EIMIL_TYPE_NUMBER, &pv_beg); PCE_get_arg_or_error(pctx, 3, EIMIL_TYPE_NUMBER, &pv_end); len = pv_target->v.mtext.len; beg = pv_beg->v.number; end = pv_end->v.number; if ((beg < 0) || (beg >= end) || (end > len)) { PCE_SEH_throw(pctx, PCE_OUT_OF_RANGE_ERROR, NULL); } EIMIL_add_prop_on_mtext(&pv_target->v.mtext, pv_prop, beg, end); EIMIL_REFCHECK(*pv_target); EIMIL_REFCHECK(*pv_prop); EIMIL_REFCHECK(*pv_beg); EIMIL_REFCHECK(*pv_end); return NULL; } DEFINE_EXEC_METHOD(delmprop) { EIMIL_value *pv; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_PROP, &pv); EIMIL_detach_prop_from_mtext(pv); EIMIL_REFCHECK(*pv); return NULL; } DEFINE_EXEC_METHOD(setmprop) { int beg, end, len; EIMIL_value *pv_target, *pv_prop, *pv_beg, *pv_end; PCE_get_arg_or_error(pctx, 0, EIMIL_TYPE_MTEXT, &pv_target); PCE_get_arg_or_error(pctx, 1, EIMIL_TYPE_PROP, &pv_prop); PCE_get_arg_or_error(pctx, 2, EIMIL_TYPE_NUMBER, &pv_beg); PCE_get_arg_or_error(pctx, 3, EIMIL_TYPE_NUMBER, &pv_end); len = pv_target->v.mtext.len; beg = pv_beg->v.number; end = pv_end->v.number; if ((beg < 0) || (beg >= end) || (end > len)) { PCE_SEH_throw(pctx, PCE_OUT_OF_RANGE_ERROR, NULL); } EIMIL_set_prop_on_mtext(&pv_target->v.mtext, pv_prop, beg, end); EIMIL_REFCHECK(*pv_target); EIMIL_REFCHECK(*pv_prop); EIMIL_REFCHECK(*pv_beg); EIMIL_REFCHECK(*pv_end); return NULL; } DEFINE_EXEC_METHOD(tblref) { return NULL; } DEFINE_EXEC_METHOD(makeprop) { EIMIL_symbol *psym; psym = PCE_get_symbol_arg(pctx, 0, EIMIL_CAT_PROPERTY); return EIMIL_construct_prop(psym); } DEFINE_EXEC_METHOD(getmprop) { EIMIL_symbol *psym; EIMIL_value *pv_mtext, *pv_beg, *pvr; psym = PCE_get_symbol_arg(pctx, 0, EIMIL_CAT_PROPERTY); PCE_get_arg_or_error(pctx, 1, EIMIL_TYPE_MTEXT, &pv_mtext); PCE_get_arg_or_error(pctx, 2, EIMIL_TYPE_NUMBER, &pv_beg); pvr = EIMIL_get_prop_from_mtext(&pv_mtext->v.mtext, psym, pv_beg->v.number); EIMIL_REFCHECK(*pv_mtext); EIMIL_REFCHECK(*pv_beg); return pvr; } DEFINE_EXEC_METHOD(findmprop) { EIMIL_symbol *psym; EIMIL_value *pv_mtext, *pv_beg, *pvr; psym = PCE_get_symbol_arg(pctx, 0, EIMIL_CAT_PROPERTY); PCE_get_arg_or_error(pctx, 1, EIMIL_TYPE_MTEXT, &pv_mtext); PCE_get_arg_or_error(pctx, 2, EIMIL_TYPE_NUMBER, &pv_beg); pvr = EIMIL_find_prop_from_mtext(&pv_mtext->v.mtext, psym, pv_beg->v.number); EIMIL_REFCHECK(*pv_mtext); EIMIL_REFCHECK(*pv_beg); return pvr; } DEFINE_EXEC_METHOD(interact) { return NULL; } DEFINE_EXEC_METHOD(match) { return NULL; } DEFINE_EXEC_METHOD(forward) { return NULL; } DEFINE_EXEC_METHOD(send) { return NULL; } DEFINE_EXEC_METHOD(set) { EIMIL_value *pv, *pvo; EIMIL_symbol *psym; ASSERT(pctx->pcur->parg && pctx->pcur->parg->pnext); psym = PCE_lookup_symbol(pctx, pctx->pcur->parg->pnext); ASSERT(psym && psym->cat == EIMIL_CAT_VARIABLE); if (!PCE_get_arg(pctx, 0, EIMIL_TYPE_ANY, &pv) == PCE_NO_MORE_ARG_ERROR) { PCE_SEH_throw(pctx, PCE_TOO_FEW_ARGUMENTS_ERROR, NULL); } if (psym->obj.v.constp) { PCE_SEH_throw(pctx, PCE_VARIABLE_CONSTANT_ERROR, NULL); } if (pv && (pv->type != psym->obj.v.type)) { PCE_SEH_throw(pctx, PCE_WRONG_TYPE_ARGUMENT_ERROR, NULL); } pvo = psym->obj.v.pv; if (pvo) EIMIL_RMREF(*pvo); psym->obj.v.pv = pv; if (pv) EIMIL_ADDREF(*pv); return pv; } DEFINE_EXEC_METHOD(return) { EIMIL_value *pv; if (!PCE_get_arg(pctx, 0, EIMIL_TYPE_ANY, &pv) == PCE_NO_MORE_ARG_ERROR) { PCE_SEH_throw(pctx, PCE_TOO_FEW_ARGUMENTS_ERROR, NULL); } PCE_SEH_throw(pctx, PCE_RETURN_JMP_ERROR, pv); return NULL; } static enum PCE_ERROR_CODE PCE_root_exception_handler( PCE_context *pctx, int ecode, void *throwarg, void *catcharg ) { /* TODO */ if (ecode == PCE_WAIT_NEXT_EVENT_ERROR) { pctx->pcur = pctx->pcur->pnext; return PCE_WAIT_NEXT_EVENT_ERROR; } EIMIL_set_error(pctx->ped, "Exception received."); return PCE_UNKNOWN_ERROR; } static enum EIMIL_ENGINE_STATUS PCE_execute( void *private ) { EIMIL_value *pv; PCE_context *pctx = (PCE_context*) private; enum PCE_ERROR_CODE r; pv = EIMIL_next_event(pctx->ped); if (pv) { PCE_set_current_event(pctx, pv); } if (PCE_SEH_start(pctx) != PCE_SUCCESS) return EIMIL_ENGINE_STATUS_ERROR; if (PCE_SEH_catch(pctx, PCE_ANY_ERROR, PCE_root_exception_handler, NULL) != PCE_SUCCESS) return EIMIL_ENGINE_STATUS_ERROR; r = PCE_SEH_try(pctx, PCE_execute_loop, NULL); if (r == PCE_SUCCESS) return EIMIL_ENGINE_STATUS_SUCCESS; else if (r == PCE_WAIT_NEXT_EVENT_ERROR) return EIMIL_ENGINE_STATUS_SUSPENDED; return EIMIL_ENGINE_STATUS_ERROR; } /******************************************************************************** initialization *********************************************************************************/ static void PCE_init_document_template() { int n; EIMIL_element_template *p; p = PCE_if_full_template; n = EIMIL_TEMPLATE_NUM(PCE_if_else_template) - 1; memcpy(p , PCE_if_else_template, n * sizeof(*p)); p += n; n = EIMIL_TEMPLATE_NUM(PCE_statement_template); memcpy(p , PCE_statement_template, n * sizeof(*p)); p = PCE_try_full_template; n = EIMIL_TEMPLATE_NUM(PCE_try_catch_template) - 1; memcpy(p , PCE_try_catch_template, n * sizeof(*p)); p += n; n = EIMIL_TEMPLATE_NUM(PCE_statement_template); memcpy(p , PCE_statement_template, n * sizeof(*p)); } int PCE_init() { PCE_init_document_template(); EIMIL_register_engine(PCE_classname, PCE_docroot, PCE_handler, PCE_execute, PCE_xmlns_uri); return 1; } /******************************************************************************** API *********************************************************************************/ #ifdef DEBUG static void dump_header( int lv, PCE_code *pc ) { int i; for (i = 0; i < lv; i++) { fputs(" ", stderr); } fprintf(stderr, "%X:", (int) pc); } void EIMIL_dump_value( EIMIL_value *pv ) { if (pv) { switch (pv->type) { case EIMIL_TYPE_BOOL: fprintf(stderr, "Bool:%d", pv->v.bool_val); break; case EIMIL_TYPE_NUMBER: fprintf(stderr, "Int:%d", pv->v.number); break; case EIMIL_TYPE_CHAR: fprintf(stderr, "Char:%c(%X)", pv->v.ch, pv->v.ch); break; case EIMIL_TYPE_MTEXT: fprintf(stderr, "MTEXT"); break; case EIMIL_TYPE_EVENT: fprintf(stderr, "EVENT"); break; case EIMIL_TYPE_PROP: fprintf(stderr, "PROP"); break; default: fprintf(stderr, "!!Unknown value:%X", pv->type); break; } } else { fprintf(stderr, "nil"); } fputc('\n', stderr); } void PCE_dump_code_internal( PCE_context *pctx, PCE_code *pc, int lv ) { char *pn; EIMIL_symbol *psym; for ( ; pc; pc = pc->pnext) { switch (pc->type) { case PCE_CODE_MAIN: dump_header(lv, pc); fprintf(stderr, "MAIN:\n"); PCE_dump_code_internal(pctx, pc->parg, lv + 1); break; case PCE_CODE_DEFUN: dump_header(lv, pc); psym = PCE_lookup_symbol(pctx, pc); fprintf(stderr, "DEFUN:%s\n", psym->name); PCE_dump_code_internal(pctx, pc->parg, lv + 1); break; case PCE_CODE_INST: if (pc->val.h == PCE_add_exec) { pn = "add"; } else if (pc->val.h == PCE_sub_exec) { pn = "sub"; } else if (pc->val.h == PCE_mul_exec) { pn = "mul"; } else if (pc->val.h == PCE_div_exec) { pn = "div"; } else if (pc->val.h == PCE_lt_exec) { pn = "lt"; } else if (pc->val.h == PCE_gt_exec) { pn = "gt"; } else if (pc->val.h == PCE_le_exec) { pn = "le"; } else if (pc->val.h == PCE_ge_exec) { pn = "ge"; } else if (pc->val.h == PCE_eql_exec) { pn = "eql"; } else if (pc->val.h == PCE_strcmp_exec) { pn = "strcmp"; } else if (pc->val.h == PCE_set_exec) { pn = "set"; } else if (pc->val.h == PCE_next_exec) { pn = "next"; } else if (pc->val.h == PCE_makeev_exec) { pn = "makeev"; } else { pn = "unknown"; } dump_header(lv, pc); fprintf(stderr, "Inst:%s\n", pn); PCE_dump_code_internal(pctx, pc->parg, lv + 1); break; case PCE_CODE_VALUE: dump_header(lv, pc); EIMIL_dump_value(pc->val.pv); break; case PCE_CODE_SYMBOL: dump_header(lv, pc); psym = PCE_lookup_symbol(pctx, pc); if (!psym) { fprintf(stderr, "!!Unknown symid:%d\n", pc->val.symid); break; } if (psym->cat != EIMIL_CAT_VARIABLE) { fprintf(stderr, "!!not variable:%s\n", psym->name); break; } fprintf(stderr, "Var:%s\n", psym->name); break; case PCE_CODE_JMP: dump_header(lv, pc); fprintf(stderr, "Jump:%x\n", (int) pc->val.pc_to); PCE_dump_code_internal(pctx, pc->parg, lv + 1); break; case PCE_CODE_COND_JMP: dump_header(lv, pc); fprintf(stderr, "Jump if:%x\n", (int) pc->val.pc_to); PCE_dump_code_internal(pctx, pc->parg, lv + 1); break; case PCE_CODE_COND_NOT_JMP: dump_header(lv, pc); fprintf(stderr, "Jump unless:%x\n", (int) pc->val.pc_to); PCE_dump_code_internal(pctx, pc->parg, lv + 1); break; default: /* TODO */ break; } } } void PCE_dump_code( PCE_context *pctx ) { PCE_dump_code_internal(pctx, pctx->pcur, 0); } #endif /* Local Variables: */ /* c-file-style: "iiim-project" */ /* End: */