UNPKG

tscc-compiler

Version:

An LALR(1) compiler compiler written in Typescript

146 lines (139 loc) 5.03 kB
import { DFA } from './dfa'; import { initArray } from '../util/initarray'; import { createClassFinder } from '../util/class-detect'; import { Arc, State } from './state'; import { compress, Table } from '../util/compress'; import { OutputStream } from '../util/io'; import { EscapeDef, escapeString } from '../util/span'; function arrayWrapper<T>(stateCount: number, classCount: number, rawTable: Arc<T>[]): Table{ let emCount: number[] = []; for(let state = 0;state < stateCount;state++){ emCount.push(0); for(let t = 0; t < classCount; t++){ rawTable[state * classCount + t] === null && (emCount[state]++); } } return { rows: stateCount, columns: classCount, isEmpty(state, c){ return rawTable[state * classCount + c] === null; }, emptyCount(c){ return emCount[c]; } }; } export class DFATable<T>{ states: State<T>[]; classCount: number; pnext: Arc<T>[]; disnext: number[]; checknext: number[]; classTable: number[]; unicodeClassTable: number[]; private _trim(){ while(this.pnext[this.pnext.length - 1] === null){ this.pnext.pop(); this.checknext.pop(); } } constructor(dfa: DFA<T>, public maxAsicii: number = 255){ function emitClassInterval(a: number, b: number, cl: number){ for(; a <= b; a++){ classTable[a] = cl; } } var cf = createClassFinder<Arc<T>>(); dfa.forEachArc((arc, from, to) => { cf.addClass(arc.chars, arc); }); var r = cf.done(); this.classCount = r.classCount; this.states = dfa.states; var classTable: number[] = this.classTable = initArray<number>(maxAsicii + 1, i => -1); var unicodeClassTable: number[] = this.unicodeClassTable = []; var rawTable = initArray<Arc<T>>(r.classCount * dfa.states.length, i => null); r.classSet.forEach((a, b, it) => { if(a > maxAsicii){ unicodeClassTable.push(it.data.id, a, b); } else if(b <= maxAsicii){ emitClassInterval(a, b, it.data.id); } else { emitClassInterval(a, maxAsicii, it.data.id); maxAsicii < b && unicodeClassTable.push(it.data.id, maxAsicii + 1, b); } for(let arc of it.data.data){ rawTable[arc.from.index * r.classCount + it.data.id] = arc; } }); var { len, dps } = compress(arrayWrapper(this.states.length, r.classCount, rawTable)); this.disnext = dps; this.pnext = initArray<Arc<T>>(len, i => null); this.checknext = initArray<number>(len, i => -1); for(let s = 0; s < this.states.length; s++){ for(let c = 0; c < this.classCount; c++){ let arc = rawTable[s * this.classCount + c]; if(arc !== null){ this.pnext[this.disnext[s] + c] = arc; this.checknext[this.disnext[s] + c] = s; } } } this._trim(); } lookup(s: number, c: number): Arc<T>{ let ind = this.disnext[s] + c; if(ind >= 0 && ind < this.pnext.length && this.checknext[ind] === s){ return this.pnext[ind]; } else { return null; } } print(os: OutputStream, escapes?: EscapeDef){ var tab = ' '; function char(c: number){ if(c >= 0x20 && c <= 0x7e){ return "'" + String.fromCharCode(c) + "'"; } else { return `\\x${c.toString(16)}`; } } function echo(s: string){ if(escapes){ s = escapeString(s, escapes); } os.writeln(s); } let tl = 0; var line = 'class table:\n' + tab; for(let c = 0; c < this.classTable.length; c++){ if(this.classTable[c] !== -1) { line += `${char(c)} -> c${this.classTable[c]}, `; tl++ > 9 && (line += `\n${tab}`, tl = 0); } } echo(line + '\n'); line = 'unicode class table:\n' + tab; tl = 0; for(let c = 0, _a = this.unicodeClassTable; c < _a.length; c += 3){ line += `\\x${_a[c + 1]}-\\x${_a[c + 2]} -> c${_a[c]}, `; tl++ > 4 && (line += `\n${tab}`, tl = 0); } echo(line + '\n'); for(let s = 0; s < this.states.length; s++){ line = `state ${s}:\n`; let state = this.states[s]; state.endAction !== null && (line += `${tab}end = ${state.endAction.id}\n`); for(let c = 0; c < this.classCount; c++){ let arc = this.lookup(s, c); arc !== null && (line += `${tab}c${c}: state ${arc.to.index}\n`); } echo(line); } } }