tscc-compiler
Version:
An LALR(1) compiler compiler written in Typescript
124 lines (109 loc) • 3.68 kB
text/typescript
import * as io from './util/io';
import { createContext } from './top/result';
import { generateCode } from './codegen/template';
export { highlight } from './parser/parser';
export { Assoc } from './grammar/token-entry';
export { setDebugger } from './util/common';
export { defineTemplate } from './codegen/template';
export { io, createContext, generateCode };
export var version = '1.0.2';
// debug
import * as debug from './debug';
export { debug };
function changeSuffix(s: string, suf: string): string{
var i = s.lastIndexOf('.');
return (i === -1 ? s : s.substr(0,i)) + suf;
}
function deleteSuffix(s: string): string{
var i = s.lastIndexOf('.');
return i === -1 ? s : s.substr(0,i);
}
export interface TSCCOptions{
/** name (path) of the input grammar file. */
inputFile: string;
/** content of grammar file, */
input: string;
/**
* name (path) of the output file, if set to `null` or `undefined`, the output file won't be generated.
* @default undefined
*/
outputFile?: string;
// interface
/** an interface object to print all the messages, */
stdout: io.OutputStream;
/** a callback used to write file. */
writeFile(path: string, content: string): any;
// options
/**
* test input. If specified, it will be parsed, and the process will be printed.
* @default null
*/
testInput?: string;
/**
* whether to print a detailed list of time costs.
* @default false
*/
printDetailedTime?: boolean;
/**
* whether to print lexical DFA tables to the output file.
* @default false
*/
printDFA?: boolean;
/**
* whether to show look-ahead tokens of items when printing parse table.
* @default false
*/
showlah?: boolean;
/**
* whether to show full item sets when printing parse table. Only kernel
* items will be printed when set to `false`
* @default false
*/
showFullItemsets?: boolean;
};
export function main(opt: TSCCOptions): number{
var stdout = opt.stdout;
var echo = (s: string | number) => stdout.writeln(s);
var ctx = createContext();
do {
var startTime = new Date();
ctx.compile(opt.input, deleteSuffix(opt.inputFile));
if(ctx.hasWarning()){
ctx.printWarning(stdout);
}
if(ctx.hasError()){
ctx.printError(stdout);
ctx.isTerminated() && echo('compilation terminated');
break;
}
if(opt.outputFile){
var out = new io.StringOS();
ctx.beginTime('generate output file');
opt.printDFA && ctx.printDFA(out);
ctx.printTable(out, opt.showlah, opt.showFullItemsets);
ctx.endTime();
opt.writeFile(opt.outputFile, out.s);
}
var current = new io.StringOS();
ctx.beginTime('generate parser code');
ctx.genCode({
save: fname => {
opt.writeFile(fname, current.s);
current = new io.StringOS();
},
write: s => current.write(s),
writeln: s => current.writeln(s)
});
ctx.endTime();
if(opt.testInput){
echo("preparing for test");
for(var line of ctx.testParse(opt.testInput.split(/[ ]+/g), msg => echo(msg))){
echo(line);
}
}
echo(`compilation done in ${(new Date().valueOf() - startTime.valueOf()) / 1000}s`);
opt.printDetailedTime && ctx.printDetailedTime(stdout);
}while(false);
echo(ctx.warningSummary());
return ctx.hasError() ? -1 : 0;
}