処理の見直し

ちょいと、ソ−スを整理しました。

SourceToHtml013.js


// 雛形ファイル名
var tempFileName = ".\\application\\template.html";

// 変換対象文字
var escapeChar = "<>&()|*+-";

// 言語タイプ
var langType = "";

// 予約語一覧
var keyword = new Object();

// 変換用オブジェクト
var convert = new Object();

//*****************************************************************************
// 主処理
//*****************************************************************************
main();

function main()
{
// コマンド引数が、2つ指定されてなければ、異常終了
if (WScript.Arguments.length < 2)
{
WScript.echo("コマンド引数が、2つ指定されてないので、終了");
return;
}

// 言語タイプを 取得する
if (!checkLangType()) return;

//入力ファイル名を 取得する
var inFileName = WScript.Arguments(0);

// 出力ファイル名を 取得する
var outFileName = WScript.Arguments(1);

// FileSystemObject を 生成
var fs = WScript.CreateObject("Scripting.FileSystemObject");

// 予約語一覧を取得しておく
if (fs.FileExists(".\\application\\" + langType + ".key"))
{
var tsKeyword = fs.OpenTextFile(".\\application\\" + langType + ".key", 1);
while (!tsKeyword.AtEndOfStream)
{
keyword[tsKeyword.ReadLine()] = true;
}
tsKeyword.Close();
}

// 雛形ファイルを 読み込み専用モードで 開く
var tsTemp = fs.OpenTextFile(tempFileName, 1);

// 出力ファイルを 新規作成モードで 開く
var tsOut = fs.OpenTextFile(outFileName, 2, -1);

// 雛形ファイルの終わりまで繰り返す
while (!tsTemp.AtEndOfStream)
{
// 雛形ファイルを 1行ずつ読む
var line = tsTemp.ReadLine();

// 入力ファイル名 を 出力
if (line.indexOf("%入力ファイル名%") >= 0)
tsOut.WriteLine(line.replace("%入力ファイル名%", fs.GetFileName(inFileName)));

// 行番号 を 出力
else if (line == "%行番号%")
putLineNo(fs, tsOut, inFileName);

// プログラムソース を 出力
else if (line == "%プログラムソース%")
SourceToHtml(fs, tsOut, inFileName, langType);

// 雛形ファイルを そのまま出力
else
tsOut.WriteLine(line);
}

// 出力ファイルを 閉じる
tsOut.Close();

// 雛形ファイルを 閉じる
tsTemp.Close();
}
//*****************************************************************************
// 言語タイプを 取得する
//*****************************************************************************
function checkLangType()
{
langType = "";

// 言語タイプを 取得する
if (WScript.Arguments.length > 2)
langType = WScript.Arguments(2).toLowerCase();

// 言語タイプが指定されてなければ、"Text" として扱う
if (langType == "") langType = "txt";

switch(langType)
{
case "vc6": // Visual C++ 6.0
case "vc7": // Visual C++.NET
case "cs7": // Visual C#.NET
case "bcb": // C++Builder
case "java": // Java
case "js": // JavaScript, JScript
case "vj6": // Visual J++ 6.0
case "vj7": // Visual J#.NET
case "vb6": // Visual Basci 6.0
case "vb7": // Visual Basci.NET
case "vba": // Visual Basic for Application
case "vbs": // VBScript
case "del": // Delphi
case "psql": // PL/SQL
case "tsql": // T-SQL
case "txt": // Text
break;

// 上記以外はエラー
default:
var msg = "言語種別の指定法 \n\n"
+ "VC6 ← Visual C++ 6.0 \n"
+ "VC7 ← Visual C++.NET \n"
+ "CS7 ← Visual C#.NET \n"
+ "BCB ← C++Builder \n"
+ "JavaJava \n"
+ "JS ← JavaScript \n"
+ "JS ← JScript \n"
+ "VJ6 ← Visual J++ 6.0 \n"
+ "VJ7 ← Visual J#.NET \n"
+ "VB6 ← Visual Basci 6.0 \n"
+ "VB7 ← Visual Basci.NET \n"
+ "VBAVBA \n"
+ "VBS ← VBScript \n"
+ "DEL ← DELPHI \n"
+ "PSQ ← PL/SQL \n"
+ "TSQ ← T-SQL \n"

WScript.echo(msg);
return false;
}

// 変換用オブジェクトに、各メソッドを割り当てる
switch(langType)
{
case "vc6": // Visual C++ 6.0
case "vc7": // Visual C++.NET
case "bcb": // C++Builder
case "java": // Java
convert.isComSingle = isComSingleCpp; // 単一行コメントか?
convert.isComMulti = isComMultiCpp; // 複数行コメントか?
convert.isString = isStringCpp; // 文字列か?
convert.isChar = isCharCpp; // 文字か?
convert.isStringLit = isStringLitCpp; // 逐語的文字列か?
convert.isIdent = isIdentCpp; // 識別子か?
convert.isNumber = isNumberCpp; // 数字か?
convert.isDirective = isDirectiveCpp; // ディレクティブか?
convert.isSpace = isSpace; // 空白か?
convert.isStringEnd = isStringEndCpp; // 文字列の 終了が あるか?
convert.isCharEnd = isCharEndCpp; // 文字の 終了が あるか?
convert.isComMultiEnd = isComMultiEndCpp; // 複数行コメントの 終了が あるか?
break;

case "cs7": // Visual C#.NET
convert.isComSingle = isComSingleCpp; // 単一行コメントか?
convert.isComMulti = isComMultiCpp; // 複数行コメントか?
convert.isString = isStringCpp; // 文字列か?
convert.isChar = isCharCpp; // 文字か?
convert.isStringLit = isStringLitCsp; // 逐語的文字列か? (C# 専用!)
convert.isIdent = isIdentCpp; // 識別子か?
convert.isNumber = isNumberCpp; // 数字か?
convert.isDirective = isDirectiveCpp; // ディレクティブか?
convert.isSpace = isSpace; // 空白か?
convert.isStringEnd = isStringEndCpp; // 文字列の 終了が あるか?
convert.isCharEnd = isCharEndCpp; // 文字の 終了が あるか?
convert.isComMultiEnd = isComMultiEndCpp; // 複数行コメントの 終了が あるか?
convert.isStringLitEnd = isStringLitEndCsp; // 逐語的文字列の 終了が あるか? (C# 専用!)
break;

// 上記以外は未対応
default:
break;
}

return true;
}
//*****************************************************************************
// 行番号 を 出力
//*****************************************************************************
function putLineNo(fs, tsOut, inFileName)
{
// 入力ファイルを 読み込み専用モードで 開く
var tsIn = fs.OpenTextFile(inFileName, 1);

// 行番号を初期化
var lineNo = 0;

// 入力ファイルの終わりまで繰り返す
while (!tsIn.AtEndOfStream)
{
// 入力ファイルを1行ずつ読む
tsIn.ReadLine();

// 行番号を書く
tsOut.WriteLine('<SPAN CLASS="LNO">' + FormatNum(++lineNo) + '</SPAN>');
}

// 入力ファイルを 閉じる
tsIn.Close();
}
//-----------------------------------------------------------------------------
// 数値の書式化 (例: 123 → "00123")
//-----------------------------------------------------------------------------
function FormatNum(num)
{
var s = "00000" + num;

return (s.substr(s.length - 5, 5));
}
//*****************************************************************************
// プログラムソース を 出力
//*****************************************************************************
function SourceToHtml(fs, tsOut, inFileName, langType)
{
// 入力ファイルを 読み込み専用モードで 開く
var tsIn = fs.OpenTextFile(inFileName, 1);

// 文脈オブジェクト
var context = new Object();

//現在の状態
context.state = "その他";

// 入力ファイルの終わりまで繰り返す
while (!tsIn.AtEndOfStream)
{
// 入力ファイルを 1行ずつ読む
context.lineIn = tsIn.ReadLine();

// TAB を 空白に 変換
context.lineIn = TabToSpace(context.lineIn);

// プログラムソース を 変換して 出力
switch(langType)
{
case "vc6":
case "vc7":
case "bcb":
case "java":
case "cs7":
tsOut.WriteLine(ConvToHtml(context));
break;

// そのまま出力
default:
tsOut.WriteLine(context.lineIn);
break;
}
}
// 入力ファイルを 閉じる
tsIn.Close();
}
//=============================================================================
// プログラムソース を 変換して 出力
//=============================================================================
function ConvToHtml(context)
{
// 変換出力用文字列
var lineOut = "";

// トークン
context.token = "";
// トークンの種類
context.type = "";

while (context.lineIn.length > 0)
{
// トークン
context.currToken = "";
// トークンの種類
context.currType = "";

if (context.state == "その他")
{
// 単一行コメントか?
if (convert.isComSingle(context.lineIn)) stateComSingle(context);
// 複数行コメントか?
else if (convert.isComMulti(context.lineIn)) stateComMultiBegin(context);
// 文字列か?
else if (convert.isString(context.lineIn)) stateString(context);
// 文字か?
else if (convert.isChar(context.lineIn)) stateChar(context);
// 逐語的文字列か?
else if (convert.isStringLit(context.lineIn)) stateStringLitBegin(context);
// 識別子か?
else if (convert.isIdent(context.lineIn)) stateIdent(context);
// 数字か?
else if (convert.isNumber(context.lineIn)) stateNumber(context);
// ディレクティブか?
else if (convert.isDirective(context.lineIn)) stateDirective(context);
// 空白か?
else if (convert.isSpace(context.lineIn)) stateSpace(context);
// それ以外なら 演算子・記号
else stateOther(context);
}
else if (context.state == "複数行コメント") stateComMulti(context);

else if (context.state == "逐語的文字列") stateStringLit(context);

// トークンの種類が変わったら
if (context.currType != context.type)
{
// トークンを出力
lineOut += putToken(context.token, context.type);
context.token = context.currToken;
context.type = context.currType;
}
// トークンの種類が同じなら
else
{
// トークンに追加
context.token += context.currToken;
}
}
// 未出力トークンを出力
lineOut += putToken(context.token, context.type);

return lineOut;
}
//-----------------------------------------------------------------------------
// トークンの種類を 判定
//-----------------------------------------------------------------------------
// 単一行コメントか?
function isComSingleCpp(arg) { return (arg.match(/^\/\//)); } // C, C++, Java, JavaScript, C#, Delphi
// 複数行コメントか? "/*"
function isComMultiCpp(arg) { return (arg.match(/^\/\*/)); } // C, C++, Java, JavaScript, C# PL/SQL, T-SQL
// 文字列か?
function isStringCpp(arg) { return (arg.match(/^"/)); } // C, C++, Java, JavaScript, C# , VB,
// 文字か?
function isCharCpp(arg) { return (arg.match(/^'/)); } // C, C++, Java, JavaScript, C#
// 逐語的文字列か?
function isStringLitCpp(arg) { return false; } // C, C++, Java, JavaScript
function isStringLitCsp(arg) { return (arg.match(/^@"/)); } // C#
// 識別子か?
function isIdentCpp(arg) { return (arg.match(/^[A-Za-z_][A-Za-z0-9_]*/)); } // C, C++, Java, JavaScript, C#, Delphi, VB, PL/SQL, T-SQL
// 数字か?
function isNumberCpp(arg) { return (arg.match(/^[0-9]/)); } // C, C++, Java, JavaScript, C#, Delphi, VB, PL/SQL, T-SQL
// ディレクティブか?
function isDirectiveCpp(arg) { return (arg.match(/^#[A-Za-z]+/)); } // C, C++, Java, JavaScript, C#
// 空白か?
function isSpace(arg) { return (arg.match(/^\s+/)); } // C, C++, Java, JavaScript, C#, Delphi, VB, PL/SQL, T-SQL
//-----------------------------------------------------------------------------
// トークンの終端を 判定
//-----------------------------------------------------------------------------
// 文字列の 終了が あるか?
function isStringEndCpp(arg) { return (arg.match(/^"([^"\\]|\\.)*"/)); } // C, C++, Java, JavaScript, C# , VB,
// 文字の 終了が あるか?
function isCharEndCpp(arg) { return (arg.match(/^'([^'\\]|\\.)*'/)); } // C, C++, Java, JavaScript, C#
// 複数行コメントの 終了が あるか?
function isComMultiEndCpp(arg) { return (arg.match(/\*\//)); } // C, C++, Java, JavaScript, C# PL/SQL, T-SQL
// 逐語的文字列の 終了が あるか?
function isStringLitEndCsp(arg) { return (arg.match(/^(""|[^"])*"/)); } // C#
//-----------------------------------------------------------------------------
// 単一行コメント
//-----------------------------------------------------------------------------
function stateComSingle(context)
{
// 「単一行コメント」として出力
context.currToken = context.lineIn;
context.currType = "コメント";
context.state = "その他";
// 入力文字列を切り詰める
context.lineIn = "";
}
//-----------------------------------------------------------------------------
// 複数行コメント 開始
//-----------------------------------------------------------------------------
function stateComMultiBegin(context)
{
// 「複一行コメントの開始」として出力
context.currToken = "/*";
context.currType = "コメント";
context.state = "複数行コメント";
// 入力文字列を 2文字 切り詰める
context.lineIn = context.lineIn.substring(2);
}
//-----------------------------------------------------------------------------
// 複数行コメント 継続
//-----------------------------------------------------------------------------
function stateComMulti(context)
{
// 終了があるか?
if (convert.isComMultiEnd(context.lineIn))
{
// 「複一行コメントの終了」として出力
context.currToken = RegExp.leftContext + "*/";
context.currType = "コメント";
context.state = "その他";
// 入力文字列を 切り詰める
context.lineIn = context.lineIn.substring(RegExp.leftContext.length + 2);
}
else
{
// 「複一行コメント」として出力
context.currToken = context.lineIn;
context.currType = "コメント";
context.state = "複数行コメント";
// 入力文字列を 切り詰める
context.lineIn = "";
}
}
//-----------------------------------------------------------------------------
// 文字列
//-----------------------------------------------------------------------------
function stateString(context)
{
// 終了があるか?
if (convert.isStringEnd(context.lineIn))
{
// 「文字列」として出力
context.currToken = RegExp.lastMatch;
context.currType = "文字列";
context.state = "その他";
// 入力文字列を 切り詰める
context.lineIn = RegExp.rightContext;
}
else
{
// 行末まで出力
context.currToken = context.lineIn;
context.currType = "文字列";
context.state = "その他";
// 入力文字列を 切り詰める
context.lineIn = "";
}
}
//-----------------------------------------------------------------------------
// 文字列
//-----------------------------------------------------------------------------
function stateChar(context)
{
// 終了があるか?
if (convert.isCharEnd(context.lineIn))
{
// 「文字」として出力
context.currToken = RegExp.lastMatch;
context.currType = "文字";
context.state = "その他";
// 入力文字列を 切り詰める
context.lineIn = RegExp.rightContext;
}
else
{
// 行末まで出力
context.currToken = context.lineIn;
context.currType = "文字";
context.state = "その他";
// 入力文字列を 切り詰める
context.lineIn = "";
}
}
//-----------------------------------------------------------------------------
// 逐語的文字列 開始
//-----------------------------------------------------------------------------
function stateStringLitBegin(context)
{
// 「逐語的文字列の開始」として出力
context.currToken = '@"';
context.currType = "文字列";
context.state = "逐語的文字列";
// 入力文字列を 2文字 切り詰める
context.lineIn = context.lineIn.substring(2);
}
//-----------------------------------------------------------------------------
// 逐語的文字列 継続
//-----------------------------------------------------------------------------
function stateStringLit(context)
{
// 終了があるか?
if (convert.isStringLitEnd(context.lineIn))
{
// 「逐語的文字列の終了」として出力
context.currToken = RegExp.lastMatch;
context.currType = "文字列";
context.state = "その他";
// 入力文字列を 切り詰める
context.lineIn = RegExp.rightContext;
}
else
{
// 「逐語的文字列」として出力
context.currToken = context.lineIn;
context.currType = "文字列";
context.state = "逐語的文字列";
// 入力文字列を 切り詰める
context.lineIn = "";
}
}
//-----------------------------------------------------------------------------
// 識別子
//-----------------------------------------------------------------------------
function stateIdent(context)
{
// 「識別子」or「予約語」として出力
context.currToken = RegExp.lastMatch;
if (keyword[context.currToken])
context.currType = "予約語";
else
context.currType = "識別子";
context.state = "その他";
// 入力文字列を 切り詰める
context.lineIn = RegExp.rightContext;
}
//-----------------------------------------------------------------------------
// 数字
//-----------------------------------------------------------------------------
function stateNumber(context)
{
if
( (context.lineIn.match(/^[0-9]*\.?[0-9]?e{1}[+-]?[0-9]*[A-Z]{0,2}/i)) // 99e99
|| (context.lineIn.match(/^[0-9]*\.[0-9]*[A-Z]{0,2}/i)) // 99.99
|| (context.lineIn.match(/^0X[0-9A-F]*[A-Z]{0,2}/i)) // 0x99
|| (context.lineIn.match(/^[0-9]*[A-Z]{0,2}/i)) // 99
)
{
// 「数字」として出力
context.currToken = RegExp.lastMatch;
context.currType = "数字";
context.state = "その他";
// 入力文字列を 切り詰める
context.lineIn = RegExp.rightContext;
}
else
{
// 「数字」として出力
context.currToken = context.lineIn.charAt(0);
context.currType = "数字";
context.state = "その他";
// 入力文字列を 1文字 切り詰める
context.lineIn = context.lineIn.substring(1);
}
}
//-----------------------------------------------------------------------------
// ディレクティブ
//-----------------------------------------------------------------------------
function stateDirective(context)
{
// 「ディレクティブ」として出力
context.currToken = RegExp.lastMatch;
context.currType = "ディレクティブ";
context.state = "その他";
// 入力文字列を 切り詰める
context.lineIn = RegExp.rightContext;
}
//-----------------------------------------------------------------------------
// 空白
//-----------------------------------------------------------------------------
function stateSpace(context)
{
// そのまま出力
context.currToken = context.lineIn.charAt(0);
context.currType = "";
context.state = "その他";
// 入力文字列を 1文字 切り詰める
context.lineIn = context.lineIn.substring(1);
}
//-----------------------------------------------------------------------------
// それ以外
//-----------------------------------------------------------------------------
function stateOther(context)
{
// 「演算子・記号」として出力
context.currToken = context.lineIn.charAt(0);
context.currType = "記号";
context.state = "その他";
// 入力文字列を 1文字 切り詰める
context.lineIn = context.lineIn.substring(1);
}
//=============================================================================
// トークンを出力
//=============================================================================
function putToken(token, type)
{
if (token.length < 1) return "";

// 変換出力用文字列
var lineOut = "";

// 1文字ずつ処理する
for (var i=0;i<token.length;i++)
{
// 1文字取り出す
var c = token.charAt(i);

if (escapeChar.indexOf(c) >= 0)
{
// 変換して出力
// "0" → "&#x30;"
lineOut += "&#x" + c.charCodeAt(0).toString(16) + ";";
}
else
{
// そのまま出力
lineOut += c;
}
}

if (type == "予約語") return '<SPAN CLASS="KEY">' + lineOut + '</SPAN>';
if (type == "コメント") return '<SPAN CLASS="COM">' + lineOut + '</SPAN>';
if (type == "文字列") return '<SPAN CLASS="STR">' + lineOut + '</SPAN>';
if (type == "文字") return '<SPAN CLASS="CHA">' + lineOut + '</SPAN>';
if (type == "識別子") return '<SPAN CLASS="IDF">' + lineOut + '</SPAN>';
if (type == "数字") return '<SPAN CLASS="NUM">' + lineOut + '</SPAN>';
if (type == "記号") return '<SPAN CLASS="DLM">' + lineOut + '</SPAN>';
if (type == "ディレクティブ") return '<SPAN CLASS="DIR">' + lineOut + '</SPAN>';
return lineOut;
}
//-----------------------------------------------------------------------------
// TAB を 空白に 変換
//-----------------------------------------------------------------------------
function TabToSpace(lineIn)
{
// 変換出力用文字列
var lineOut = "";

// 現在位置
var pos = 0;

// 1文字ずつ処理する
for (var i=0;i<lineIn.length;i++)
{
// 1文字取り出す
var c = lineIn.substr(i, 1);

// TAB か?
if (c == "\t")
{
// 空白何文字分に置き換えればよいか
var num = 4 - (pos % 4);
// 現在位置を加算
pos += num;
// 変換して出力
lineOut += " ".substr(0, num);
}
else
{
// 現在位置を加算
if (escape(c).length < 4)
pos++;
else
pos += 2;
// そのまま出力
lineOut += c;
}
}

//行末の空白を削除
return lineOut.replace(/ +$/,"");
}

実行形式 (Visual C++ 6.0)


Z:\>SourceToHtml013.js TEST.cpp TEST.html vc6

実行形式 (Visual C++.NET)


Z:\>SourceToHtml013.js TEST.h TEST.html vc7

実行形式 (C++Builder)


Z:\>SourceToHtml013.js TEST.cpp TEST.html bcb

実行形式 (Visual C#.NET)


Z:\>SourceToHtml013.js TEST.cs TEST.html cs7