UNPKG

jaycc

Version:

### the Javascript C Compiler

201 lines (200 loc) 5.02 kB
/* int main() { return 5; } */ let regexplist; regexplist = [ { regexp: /^\s/, tokenname: 'whitespace' }, { regexp: /^\(/, tokenname: 'openround' }, { regexp: /^\)/, tokenname: 'closeround' }, { regexp: /^{/, tokenname: 'opencurly' }, { regexp: /^}/, tokenname: 'closecurly' }, { regexp: /^;/, tokenname: 'semicolon' }, { regexp: /^int/, tokenname: 'keyword' }, { regexp: /^return/, tokenname: 'keyword' }, { regexp: /^[0-9]+/, tokenname: 'numberconst' }, { regexp: /^[a-zA-Z_'][a-zA-Z_0-9']+/, tokenname: 'identifier' } ]; let keyword; let whitespace; let identifier; let openround; let closeround; let opencurly; let closecurly; let semicolon; let numberconst; let eof; let eq; keyword = (arg = '') => ({ tag: 'keyword', contents: arg }); whitespace = () => ({ tag: 'whitespace', contents: undefined }); identifier = (arg = '') => ({ tag: 'identifier', contents: arg }); openround = () => ({ tag: 'openround', contents: undefined }); closeround = () => ({ tag: 'closeround', contents: undefined }); opencurly = () => ({ tag: 'opencurly', contents: undefined }); closecurly = () => ({ tag: 'closecurly', contents: undefined }); semicolon = () => ({ tag: 'semicolon', contents: undefined }); numberconst = (arg = 0) => ({ tag: 'numberconst', contents: arg }); eof = () => ({ tag: '<eof>', contents: undefined }); eq = (t1, t2) => (t1 && t2 && (t1.tag == t2.tag)); class Lexer { input; token; constructor(str) { this.input = str; this.lex(); return this; } lex() { let regexp; let tokenname; let entry; let input; let inputarr; let n; let matcharr; let token; let tmp; let numconst; input = this.input; if (!input.length) { this.token = eof(); return void 0; } entry = regexplist.find((x) => (input.match(x.regexp)) ? true : false); if (!entry) throw "Parse error (lexer)"; regexp = entry.regexp; tokenname = entry.tokenname; matcharr = input.match(regexp); // console.log('matcharr: ', matcharr); n = matcharr[0].length; inputarr = input.split(''); while (n--) inputarr.shift(); input = inputarr.join(''); token = null; switch (tokenname) { case 'whitespace': token = whitespace(); break; case 'openround': token = openround(); break; case 'closeround': token = closeround(); break; case 'opencurly': token = opencurly(); break; case 'closecurly': token = closecurly(); break; case 'semicolon': token = semicolon(); break; case 'identifier': tmp = matcharr[0]; token = identifier(tmp); break; case 'keyword': tmp = matcharr[0]; token = keyword(tmp); break; case 'numberconst': tmp = matcharr[0]; numconst = Number.parseInt(tmp); token = numberconst(numconst); break; default: throw 'Parse error (lexer)'; } if (!token) throw 'Parse error (lexer)'; this.input = input; this.token = token; return void 0; } } class FileLexer { input; tokens; constructor(str) { let ret; if (!str) throw "Empty input string"; this.input = str; this.tokens = []; ret = this.lexfile(); if (!ret) throw "Parse error (lexing)"; } lexfile() { let ret; ret = this.lexfile_([], this.input); this.tokens = this.tokens.filter((x) => (!eq(x, whitespace()))); return ret; } lexfile_(ts, str) { let tok; let toks; let str_; let lxr; try { lxr = new Lexer(str); if (lxr.token) { tok = lxr.token; str_ = lxr.input; } else throw "Parse error (lexer)"; toks = ts; toks.push(tok); if (eq(tok, eof())) { this.tokens = toks; this.input = ''; return true; } else return this.lexfile_(toks, str_); } catch (err) { if (err instanceof String) console.error(err); return false; } } } export { Lexer, FileLexer, eq }; export { keyword, whitespace, identifier, openround, closeround, opencurly, closecurly, semicolon, numberconst, eof };