304 lines
11 KiB
JavaScript
304 lines
11 KiB
JavaScript
|
|
||
|
|
||
|
|
||
|
/***********************************************************************/
|
||
|
/* */
|
||
|
/* 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 */
|