<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");
};
変更前のソースはリンク先をご覧下さい。