/***********************************************************************/ /* */ /* Objective Caml */ /* */ /* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ /* */ /* Copyright 1996 Institut National de Recherche en Informatique et */ /* en Automatique. All rights reserved. This file is distributed */ /* under the terms of the GNU Library General Public License, with */ /* the special exception on linking described in file ../LICENSE. */ /* */ /***********************************************************************/ /* $Id: parsing.c 8983 2008-08-06 09:38:25Z xleroy $ */ /* The PDA automaton for parsers generated by camlyacc */ /* The pushdown automata */ /** * caml_lex_array("abcd") * [25185, 25699] * @param s * @returns {any[]} * TODO: duplicated with module {!Caml_lex} */ function caml_lex_array(s) { var l = s.length / 2; var a = new Array(l); for (var i = 0; i < l; i++) a[i] = (s.charCodeAt(2 * i) | (s.charCodeAt(2 * i + 1) << 8)) << 16 >> 16; return a; } /** * Note that TS enum is not friendly to Closure compiler * @enum{number} */ var Automata = { START: 0, LOOP: 6, TOKEN_READ: 1, TEST_SHIFT: 7, ERROR_DETECTED: 5, SHIFT: 8, SHIFT_RECOVER: 9, STACK_GROWN_1: 2, REDUCE: 10, STACK_GROWN_2: 3, SEMANTIC_ACTION_COMPUTED: 4 }; /** * @enum{number} */ var Result = { READ_TOKEN: 0, RAISE_PARSE_ERROR: 1, GROW_STACKS_1: 2, GROW_STACKS_2: 3, COMPUTE_SEMANTIC_ACTION: 4, CALL_ERROR_FUNCTION: 5 }; var PARSER_TRACE = false; ; var parse_engine = (function (tables /* parser_table */, env /* parser_env */, cmd /* parser_input*/, arg /* Obj.t*/) { var ERRCODE = 256; //var START = 0; //var TOKEN_READ = 1; //var STACKS_GROWN_1 = 2; //var STACKS_GROWN_2 = 3; //var SEMANTIC_ACTION_COMPUTED = 4; //var ERROR_DETECTED = 5; //var loop = 6; //var testshift = 7; //var shift = 8; //var shift_recover = 9; //var reduce = 10; // Parsing.parser_env var env_s_stack = 's_stack'; // array var env_v_stack = 'v_stack'; // array var env_symb_start_stack = 'symb_start_stack'; // array var env_symb_end_stack = 'symb_end_stack'; // array var env_stacksize = 'stacksize'; var env_stackbase = 'stackbase'; var env_curr_char = 'curr_char'; var env_lval = 'lval'; // Obj.t var env_symb_start = 'symb_start'; // position var env_symb_end = 'symb_end'; // position var env_asp = 'asp'; var env_rule_len = 'rule_len'; var env_rule_number = 'rule_number'; var env_sp = 'sp'; var env_state = 'state'; var env_errflag = 'errflag'; // Parsing.parse_tables // var _tbl_actions = 1; var tbl_transl_const = 'transl_const'; // array var tbl_transl_block = 'transl_block'; // array var tbl_lhs = 'lhs'; var tbl_len = 'len'; var tbl_defred = 'defred'; var tbl_dgoto = 'dgoto'; var tbl_sindex = 'sindex'; var tbl_rindex = 'rindex'; var tbl_gindex = 'gindex'; var tbl_tablesize = 'tablesize'; var tbl_table = 'table'; var tbl_check = 'check'; // var _tbl_error_function = 14; // var _tbl_names_const = 15; // var _tbl_names_block = 16; if (!tables.preprocessed) { tables.defred = caml_lex_array(tables[tbl_defred]); tables.sindex = caml_lex_array(tables[tbl_sindex]); tables.check = caml_lex_array(tables[tbl_check]); tables.rindex = caml_lex_array(tables[tbl_rindex]); tables.table = caml_lex_array(tables[tbl_table]); tables.len = caml_lex_array(tables[tbl_len]); tables.lhs = caml_lex_array(tables[tbl_lhs]); tables.gindex = caml_lex_array(tables[tbl_gindex]); tables.dgoto = caml_lex_array(tables[tbl_dgoto]); tables.preprocessed = true; } var res; var n, n1, n2, state1; // RESTORE var sp = env[env_sp]; var state = env[env_state]; var errflag = env[env_errflag]; exit: for (;;) { //console.error("State", Automata[cmd]); switch (cmd) { case Automata.START: state = 0; errflag = 0; // Fall through case Automata.LOOP: n = tables.defred[state]; if (n != 0) { cmd = Automata.REDUCE; break; } if (env[env_curr_char] >= 0) { cmd = Automata.TEST_SHIFT; break; } res = Result.READ_TOKEN; break exit; /* The ML code calls the lexer and updates */ /* symb_start and symb_end */ case Automata.TOKEN_READ: if (typeof arg !== 'number') { env[env_curr_char] = tables[tbl_transl_block][arg.TAG | 0 /* + 1 */]; env[env_lval] = arg._0; // token carries payload } else { env[env_curr_char] = tables[tbl_transl_const][arg /* + 1 */]; env[env_lval] = 0; // const token } if (PARSER_TRACE) { console.error("State %d, read token", state, arg); } // Fall through case Automata.TEST_SHIFT: n1 = tables.sindex[state]; n2 = n1 + env[env_curr_char]; if (n1 != 0 && n2 >= 0 && n2 <= tables[tbl_tablesize] && tables.check[n2] == env[env_curr_char]) { cmd = Automata.SHIFT; break; } n1 = tables.rindex[state]; n2 = n1 + env[env_curr_char]; if (n1 != 0 && n2 >= 0 && n2 <= tables[tbl_tablesize] && tables.check[n2] == env[env_curr_char]) { n = tables.table[n2]; cmd = Automata.REDUCE; break; } if (errflag <= 0) { res = Result.CALL_ERROR_FUNCTION; break exit; } // Fall through /* The ML code calls the error function */ case Automata.ERROR_DETECTED: if (errflag < 3) { errflag = 3; for (;;) { state1 = env[env_s_stack][sp /* + 1*/]; n1 = tables.sindex[state1]; n2 = n1 + ERRCODE; if (n1 != 0 && n2 >= 0 && n2 <= tables[tbl_tablesize] && tables.check[n2] == ERRCODE) { cmd = Automata.SHIFT_RECOVER; break; } else { if (sp <= env[env_stackbase]) return Result.RAISE_PARSE_ERROR; /* The ML code raises Parse_error */ sp--; } } } else { if (env[env_curr_char] == 0) return Result.RAISE_PARSE_ERROR; /* The ML code raises Parse_error */ env[env_curr_char] = -1; cmd = Automata.LOOP; break; } // Fall through case Automata.SHIFT: env[env_curr_char] = -1; if (errflag > 0) errflag--; // Fall through case Automata.SHIFT_RECOVER: if (PARSER_TRACE) { console.error("State %d: shift to state %d", state, tables.table[n2]); } state = tables.table[n2]; sp++; if (sp >= env[env_stacksize]) { res = Result.GROW_STACKS_1; break exit; } // Fall through /* The ML code resizes the stacks */ case Automata.STACK_GROWN_1: env[env_s_stack][sp /* + 1 */] = state; env[env_v_stack][sp /* + 1 */] = env[env_lval]; env[env_symb_start_stack][sp /* + 1 */] = env[env_symb_start]; env[env_symb_end_stack][sp /* + 1 */] = env[env_symb_end]; cmd = Automata.LOOP; break; case Automata.REDUCE: if (PARSER_TRACE) { console.error("State %d : reduce by rule %d", state, n); } var m = tables.len[n]; env[env_asp] = sp; env[env_rule_number] = n; env[env_rule_len] = m; sp = sp - m + 1; m = tables.lhs[n]; state1 = env[env_s_stack][sp - 1]; // n1 = tables.gindex[m]; n2 = n1 + state1; if (n1 != 0 && n2 >= 0 && n2 <= tables[tbl_tablesize] && tables.check[n2] == state1) state = tables.table[n2]; else state = tables.dgoto[m]; if (sp >= env[env_stacksize]) { res = Result.GROW_STACKS_2; break exit; } // Fall through /* The ML code resizes the stacks */ case Automata.STACK_GROWN_2: res = Result.COMPUTE_SEMANTIC_ACTION; break exit; /* The ML code calls the semantic action */ case Automata.SEMANTIC_ACTION_COMPUTED: env[env_s_stack][sp /* + 1 */] = state; env[env_v_stack][sp /* + 1*/] = arg; var asp = env[env_asp]; env[env_symb_end_stack][sp /* + 1*/] = env[env_symb_end_stack][asp /* + 1*/]; if (sp > asp) { /* This is an epsilon production. Take symb_start equal to symb_end. */ env[env_symb_start_stack][sp /* + 1*/] = env[env_symb_end_stack][asp /*+ 1*/]; } cmd = Automata.LOOP; break; /* Should not happen */ default: return Result.RAISE_PARSE_ERROR; } } // SAVE env[env_sp] = sp; env[env_state] = state; env[env_errflag] = errflag; return res; }); var set_parser_trace = (function (v) { var old = PARSER_TRACE; PARSER_TRACE = v; return old; }); export { parse_engine , set_parser_trace , } /* Not a pure module */