tscc-compiler
Version:
An LALR(1) compiler compiler written in Typescript
147 lines (142 loc) • 5.04 kB
text/typescript
import { Grammar } from './grammar';
import { OutputStream } from '../util/io';
import { Action, Item, ItemSet } from './item-set';
import { List } from '../util/list';
import { convertTokenToString } from './token-entry';
import { EscapeDef, escapeString } from '../util/span';
export interface IParseTable{
readonly g: Grammar;
readonly stateCount: number;
defred: number[];
lookupShift(state: number, token: number): Item;
lookupGoto(state: number, nt: number): Item;
};
export function printParseTable(
os: OutputStream,
cela: IParseTable,
doneList: List<ItemSet>,
showlah: boolean,
showFullItemsets: boolean,
escapes?: EscapeDef
){
var g = cela.g;
var tokenCount = g.tokenCount;
var ntCount = g.nts.length;
var tab = ' ';
function echo(s: string){
if(escapes){
s = escapeString(s, escapes);
}
os.writeln(s);
}
doneList.forEach(function(set){
var i = set.stateIndex;
var shift = '';
var reduce = '';
var gotot = '';
var defred = '';
echo(`state ${i}`);
set.forEach(function(item){
(showFullItemsets || item.isKernel) && echo(tab + item.toString({ showlah }));
});
if(cela.defred[i] !== -1){
var def = cela.defred[i];
echo(`${tab}default action: reduce with rule ${def} (${g.rules[def].lhs.sym})`);
}
else {
echo(tab + 'no default action');
}
for(var j = 0;j < tokenCount;j++){
var item = cela.lookupShift(i,j);
if(item !== null && item !== Item.NULL){
if(item.actionType === Action.SHIFT){
shift += `${tab}${convertTokenToString(g.tokens[j])} : shift, and go to state ${item.shift.stateIndex}\n`;
}
else {
reduce += `${tab}${convertTokenToString(g.tokens[j])} : reduce with rule ${item.rule.index} (${item.rule.lhs.sym})\n`;
}
}
}
for(var j = 0;j < ntCount;j++){
var item = cela.lookupGoto(i,j);
if(item !== null){
gotot += `${tab}${g.nts[j].sym} : go to state ${item.shift.stateIndex}\n`;
}
}
var line = shift + reduce + gotot;
echo(line);
os.writeln();
});
}
export class ParseTable implements IParseTable{
g: Grammar;
stateCount: number;
shift: Item[];
gotot: Item[];
defred: number[] = null;
constructor(g: Grammar, stateCount: number){
this.g = g;
var tokenCount = g.tokenCount;
var ntCount = g.nts.length;
this.stateCount = stateCount;
this.shift = new Array(tokenCount * stateCount);
this.gotot = new Array(ntCount * stateCount);
for(var i = 0;i < this.shift.length;i++){
this.shift[i] = null;
}
for(var i = 0;i < this.gotot.length;i++){
this.gotot[i] = null;
}
}
forEachShift(cb: (it: Item, state: number, token: number) => any){
for(let state = 0; state < this.stateCount; state++){
for(let tk = 0; tk < this.g.tokens.length; tk++){
let item = this.lookupShift(state, tk);
item && cb(item, state, tk);
}
}
}
forEachGoto(cb: (it: Item, state: number, nt: number) => any){
for(let state = 0; state < this.stateCount; state++){
for(let nt = 0; nt < this.g.nts.length; nt++){
let item = this.lookupGoto(state, nt);
item && cb(item, state, nt);
}
}
}
lookupShift(state: number, token: number): Item{
return this.shift[this.g.tokenCount * state + token];
}
lookupGoto(state: number, nt: number): Item{
return this.gotot[this.g.nts.length * state + nt];
}
private _getDefRed(state: number, apool: number[]): number{
for(let i = 0; i < apool.length; i++){
apool[i] = 0;
}
for(let tk = 0; tk < this.g.tokenCount; tk++){
let item = this.lookupShift(state, tk);
item && item.actionType === Action.REDUCE && apool[item.rule.index]++;
}
let ret = 0;
for(let i = 0;i < apool.length;i++){
apool[i] > apool[ret] && (ret = i);
}
return apool[ret] > 0 ? ret : -1;
}
findDefAct(){
this.defred = new Array(this.stateCount);
let apool = new Array(this.g.rules.length);
for(let i = 0;i < this.stateCount; i++){
let def = this._getDefRed(i, apool);
this.defred[i] = def;
if(def !== -1){
for(let tk = 0;tk < this.g.tokens.length;tk++){
let item = this.lookupShift(i, tk);
item && item.actionType === Action.REDUCE && item.rule.index === def &&
(this.shift[this.g.tokenCount * i + tk] = null);
}
}
}
}
}