<head> <meta charset="UTF-8"> <title>JavaScriptでプログラミング - BASIC Parser 0.1</title> <link type="text/css" rel="stylesheet" href="lib/jasmine-1.3.1/jasmine.css"> <link type="text/css" rel="stylesheet" href="css/spec.css"> <link type="text/css" rel="stylesheet" href="css/shCoreEclipse.css"> <link type="text/css" rel="stylesheet" href="css/shThemeEclipse.css"> <script type="text/javascript" src="js/XRegExp.js"></script> <script type="text/javascript" src="js/shCore.js"></script> <script type="text/javascript" src="js/shBrushJScript.js"></script> <script type="text/javascript" src="js/shBrushXml.js"></script> <script type="text/javascript" src="js/shBrushCss.js"></script> <script type="text/javascript" src="lib/jasmine-1.3.1/jasmine.js"></script> <script type="text/javascript" src="lib/jasmine-1.3.1/jasmine-html.js"></script> <!-- include source files here... --> <script type="text/javascript" src="js/generator03/source01.js"></script> <script type="text/javascript" src="js/generator03/lex03.js"></script> <script type="text/javascript" src="js/generator03/generator03.js"></script> <!-- include spec files here... --> <script type="text/javascript" src="js/generator03/sourcespec01.js"></script> <script type="text/javascript" src="js/generator03/lexspec03.js"></script> <script type="text/javascript" src="js/generator03/generatorspec03.js"></script>
構文の定義を EBNFParser に渡す処理が、HTML ファイルの <head> タグの最後に置いてあります。 これは色々な構文を試すときも js ファイルのほうを変更しなくて済ますためです。
63行以降は Jasmine によるテスト結果を HTML 上で展開するレポーターと呼ばれる部分です。前回から変更ありません。
<script type="text/javascript"> // define BASIC syntax var gapFree = ["int", "text"]; var basicSyntax = "program = {line}, eof.\n"; basicSyntax += "line = int, statements, [comment], eol.\n"; basicSyntax += "comment = ('REM' | sq), any.\n"; basicSyntax += "statements = {statement, ':'}, (comment | statement).\n"; basicSyntax += "statement = (dim | assign | for | next | print | if | goto | end).\n"; basicSyntax += "dim = 'DIM', array.\n"; basicSyntax += "array = identifier, '(', int, ')'.\n"; basicSyntax += "identifier = upper, {upper | digit}, ['$'].\n"; basicSyntax += "int = digit, {digit}.\n"; basicSyntax += "assign = {variable | array}, '=', expression.\n"; basicSyntax += "variable = identifier.\n"; basicSyntax += "for = 'FOR', variable, '=', expression, 'TO', expression.\n"; basicSyntax += "next = 'NEXT', [variable, {',', variable}].\n"; basicSyntax += "print = 'PRINT', expression, [';'].\n"; basicSyntax += "if = 'IF', expression, 'THEN', (int | statement).\n"; basicSyntax += "goto = 'GOTO', int.\n"; basicSyntax += "end = 'END'.\n"; basicSyntax += "expression = and, {'OR', and}.\n"; basicSyntax += "and = not, {'AND', not}.\n"; basicSyntax += "not = ['NOT'], condition.\n"; basicSyntax += "condition = sum, ('=' | '<>' | '<' | '>' | '<=' | '>='), sum.\n"; basicSyntax += "sum = mod, {('+' | '-'), mod}.\n"; basicSyntax += "mod = div, {'MOD', div}.\n"; basicSyntax += "div = term, {'\\\\', term}.\n"; basicSyntax += "term = minus, {('*' | '/'), minus}.\n"; basicSyntax += "minus = ['-'], power.\n"; basicSyntax += "power = {factor, '^'}, factor.\n"; basicSyntax += "factor = ('(', expression, ')' | varialbe | array | int | string).\n"; basicSyntax += "string = '\"', {any}, '\"'.\n"; var ebnf = new EBNFParser(basicSyntax, gapFree, "BASIC", "0.1"); SyntaxHighlighter.all(); (function() { var jasmineEnv = jasmine.getEnv(); jasmineEnv.updateInterval = 1000; var htmlReporter = new jasmine.HtmlReporter(); jasmineEnv.addReporter(htmlReporter); jasmineEnv.specFilter = function(spec) { return htmlReporter.specFilter(spec); }; var currentWindowOnload = window.onload; window.onload = function() { if (currentWindowOnload) { currentWindowOnload(); } execJasmine(); }; function execJasmine() { jasmineEnv.execute(); } })(); </script>また、<body> タグの実行結果のところに直接スクリプトを書いてあります。 これは結果に対して SyntaxHighlighter を使用するためです。
<h2>実行結果</h2> 以下は今回使用する BASIC の構文です。連載「BASICでコンバータを作る」の最初に紹介した2つのプログラム Q0.BAS と P1-1.BAS に含まれる構文だけを抽出しています。 <script type="text/javascript"> // get element from HTML and set text (code) var html = '<pre class="code">\n'; html += basicSyntax; html += '</pre>\n'; document.writeln(html); </script> 上記の BASIC の構文の文字列を EBNFParser に渡し、BASICParser のコードを以下の通り生成しました。 字下げは Visual Studio Code 等のツールで簡単にできるので行っていません。 <script type="text/javascript"> // get element from HTML and set text (code) var html = "<pre class=\"brush: js; class-name: 'list'\">\n"; html += ebnf.syntax(); html += "</pre>\n"; document.writeln(html); </script>
/** * symbol = '=' | ',' | '.' | '|' | '+' | '-' | '*' | '/' | '\\' | '^' | * ':' | ';' | '[' | ']' | '{' | '}' | '(' | ')' | '<' | '>' | '"' | '$'. * @return {String} code generated if matched, null if not matched * @since 0.32 */ EBNFParser.prototype.symbol = function() { var match = []; var save = this.ptr; var n = -1; this.sp(); match[++n] = this.text('='); if (!match[n]) { n--; this.sp(); match[++n] = this.text(','); } if (!match[n]) { n--; this.sp(); match[++n] = this.text('.'); } if (!match[n]) { n--; this.sp(); match[++n] = this.text('|'); } if (!match[n]) { n--; this.sp(); match[++n] = this.text('+'); } if (!match[n]) { n--; this.sp(); match[++n] = this.text('-'); } if (!match[n]) { n--; this.sp(); match[++n] = this.text('*'); } if (!match[n]) { n--; this.sp(); match[++n] = this.text('/'); } if (!match[n]) { n--; this.sp(); match[++n] = this.text('\\'); } if (!match[n]) { n--; this.sp(); match[++n] = this.text('^'); } if (!match[n]) { n--; this.sp(); match[++n] = this.text(':'); } if (!match[n]) { n--; this.sp(); match[++n] = this.text(';'); } if (!match[n]) { n--; this.sp(); match[++n] = this.text('['); } if (!match[n]) { n--; this.sp(); match[++n] = this.text(']'); } if (!match[n]) { n--; this.sp(); match[++n] = this.text('{'); } if (!match[n]) { n--; this.sp(); match[++n] = this.text('}'); } if (!match[n]) { n--; this.sp(); match[++n] = this.text('('); } if (!match[n]) { n--; this.sp(); match[++n] = this.text(')'); } if (!match[n]) { n--; this.sp(); match[++n] = this.text('<'); } if (!match[n]) { n--; this.sp(); match[++n] = this.text('>'); } if (!match[n]) { n--; this.sp(); match[++n] = this.text('"'); } if (!match[n]) { n--; this.sp(); match[++n] = this.text('$'); } if (!match[n]) { this.ptr = save; return null; } return this.run(n, match, "symbol"); };変更前のソースはリンク先をご覧下さい。