はじめに
前回は、VBAを字句解析する簡単なサンプルプログラムを作成しました。
今回は、VBAの構文解析する前提としてVBAの予約語を定義したいと思います。
あわせてVBA翻訳のサンプルVBAを提示します。
前提
- OS : Windows7以上
- PoweShellのターミナルで実行
- VSCodeでコード編集
- node.js環境構築済み
VBEのオブジェクトブラウザーからVBAの予約語を取り出す
VBEとはVBAを編集するためのExcelに同梱されたエディターです。
ExcelからAtl+F11で起動できます。
VBAのライブラリの定義をここから参照して予約語をまとめます。
赤丸のボタンをマウスでクリックします。
すべてのライブラリと表示のあるドロップボックスのリストからVBAを選択します。
クラスのリストボックスのCollectionを選択します。Collectionのメンバーのリストが表示されます。
この内容を以下のように定義してみます。
var vba_Module_Collection = [Add, Count, Item, Remove];
同様にクラスのリストに含まれる、モジュール、クラス、Enumの各メンバーを定義したのが
以下となります。
var vba_Module_Collection = [Add, Count, Item, Remove];
var vba_Module_ColorConstans = [vbBlack, vbBlue, vbCyan, vbGreen, vbMagenta, vbRed,vbWhite, vbYellow];
var vba_Module_Constans = [vbBack, vbCr,vbCrLf, vbFormFeed, vbLf, vbNewLine, vbNullChar, vbNullString, vbObjectError, vbTab, vbVerticalTab];
var vba_Module_Conversion = [Cbool, CByte, Ccur, CDate, CDbl, CDec, Cint, Clng, CLngPtr, CSng, CStr, CVar, CVDate, CVErr, Error, Error$, Fix, Hex, Hex$, Int, Oct, Oct$, Str, Str$, Val];
var vba_Module_DateTime = [Calendar, Date, Date$, DateAdd, DateDiff, DatePart, DteSerial, DateValue, Day, Hour, Minute, Month, Now, Second, Time, Time$, Timer, TimeSerial, TimeValue, Weekday, Year];
var vba_Class_ErrObject = [Clear, Description, HelpContext, HelpFile, LastDllError, Number, Raise, Source];
var vba_Module_FileSystem = [ChrDir, ChrDrive, CurDrive, CurDir, CurDir$, Dir, EOF, FileAttr, FileCopy, FileDateTime, FileLen, GetAttr, Kill, Loc, LOF, MkDir, Reset, RmDir, Seek, SetAttr];
var vba_Class_Financial = [DDB, FV, Ipmt, IRR, MIRR, NPer, NPV, Pmt, PPmt, PV, Rate, SLN, SYD];
var vba_Enum_FromShowConstants = [vbModal, vbModeless];
var vba_Class_Global = [Load, Unload, UserForms];
var vba_Module_Information = [Err, IMEState, IsArray, IsDate, IsEmpty, IsError, IsMissing, IsNull, IsNumeric, IsObject, QBClor, RGB, TypeName, VarType];
var vba_Module_Interaction = [AppActivate, Beep, CallByName, Choose, Command, Command$,CreateObject, DeleteSetting, DoEvents, Environ, Environ$, GetAllSettings, GetObject, GetSetting, IIF, InputBox, MsgBox, Patition, SaveSetting, SendKeys, Shell, Switch];
var vba_Module_KeyCodeConstants = [vbKey0, vbKey1, vbKey2, vbKey3, vbKey4, vbKey5, vbKey6, vbKey7, vbKey8, vbKey9, vbKeyA, vbKeyAdd, vbKeyB, vbKeyBack, vbKeyC, vbKeyCancel, vbKeyCapital, vbKeyClear, vbKeyControl, vbKeyD, vbKeyDecimal, vbKeyDelete, vbKeyDivide, vbKeyDown, vbKeyE, vbKeyEnd, vbKeyEscape, vbKeyExecute, vbKeyF, vbKeyF1, vbKeyF10, vbKeyF11, vbKeyF12, vbKeyF13, vbKeyF14, vbKeyF15, vbKeyF16, vbKeyF2, vbKeyF3, vbKeyF4, vbKeyF5, vbKeyF6, vbKeyF7, vbKeyF8, vbKeyF9, vbKeyG, vbKeyH, vbKeyHelp, vbKeyHome, vbKeyI, vbKeyInsert, vbKeyJ, vbKeyK, vbKeyL, vbKeyLButton, vbKeyLeft, vbKeyM, vbKeyMButton, vbKeyMenu, vbKeyMultiply, vbKeyN, vbKeyNumLock, vbKeyNumpad0, vbKeynumpad1,vbKeynumpad2, vbKeynumpad3, vbKeynumpad4, vbKeynumpad5, vbKeynumpad6, vbKeynumpad7, vbKeynumpad8, vbKeynumpad9, vbKeyO, vbKeyP, vbKeyPageDown, vbKeyPageUp, vbKeyPause, vbKeyPrint, vbKeyQ, vbKeyR, vbKeyRButton, vbKeyReturn, vbKeyRight, vbKeyS, vbKeySelect, vbKeySeparator, vbKeyShift, vbKeySnapshot, vbKeySpace, vbKeySubtract, vbKeyT, vbKeyTab, vbKeyU, vbKeyUp, vbKeyV, vbKeyW, vbKeyX, vbKeyY, vbKeyZ];
var vba_Module_Math = [Abs, Atn, Cos, Exp, Log, Randomize, Rnd, Round, Sgn, Sin, Sqr, Tan];
var vba_Module_Strings = [Asc, AscB, AscW, Chr, Chr$, ChrB, ChrB$, ChrW, ChrW$, Filter, Format, Format$, FormatCurrncy, FormatDateTime, FormatNumber, FormatPercent, InStr, InStrB, InStrRev, join, LCase, LCase$, Left, Left$, LeftB, LeftB$, Len, LenB, LTrim, LTrim$, Mid, Mid$, MidB, MidB$, MonthName, Replace, Right, Right$, RightB, RightB$, RTrim, RTrim$, Space, Space$, Split, StrComp, StrConv, String, String$, StrReverse, Trim, Trim$, UCase, UCase$, WeekdayName];
var vba_Module_SystemColorConstants = [vb3DDKShadow, vb3DFace, vb3DHighlight, vb3DLight, vb3DShadow, vbActiveBorder, vbActiveTitleBar, vbApplicationWorkspace, vbButtonFace, vbButtonShadow, vbButtonText, vbDesktop, vbGrayText, vbHiglight, vbHiglightText, vbInactiveBorder, vbInactiveCaptionText, vbInactiveTitleBar, vbInfoBackground, vbInfoText, vbMenuBar, vbMenuText, vbMsgBox, vbMsgBoxText, vbScrollBars, vbTitleBarText, vbWindowBackground, vbWindowFrame, vbWindowText];
var vba_Enum_vbAppWinStyle = [vbHide, vbMaximizedFocus, vbMinimizedFocus, vbMinimizedNoFocus, vbNormalFocus, vbNormalNoFocus];
var vba_Enum_vbCalendar = [vbCalGreg, vbCalHijri];
var vba_Enum_vbCallType = [vbGet, vbLet, vbMethod, vbSet];
var vba_Enum_vbComperMrthod = [vbBinaryCompare, vbDatabaseCompare, vbTextCompare];
var vba_Enum_vbDateTimeFormat = [vbGreneralDate, vbLongDate, vbLongTime, vbShortDate, vbShortTime];
var vba_Enum_vbDayOfWeek = [vbFriday, vbMonday, vbSturday, vbSunday, vbThursday,vbTuesday,vbUseSystemDayOfWeek, vbWendnesday];
var vba_Enum_vbFileAttribute = [vbAlias, vbArchive, vbDirectory, vbHidden, vbNormal, vbReadOnly, vbSystem, vbVolume];
var vba_Enum_vbFirstWeekOfYear = [vbFirstFourDays, vbFirstFullWeek, vbFirstJan1, vbUseSystem];
var vba_Enum_vbIMEStatus = [vbIMEAlphaDbl, vbIMEAlphaSng, vbIMEDisable, vbIMEHiragana, vbIMEKatakanaDbl, vbIMEKatakanaSng, vbIMEModeAlpha, vbIMEModeAlphaFull, vbIMEModeDisable, vbIMEModeHangul, vbIMEModeHangulFull, vbIMEModeHiragana, vbIMEModeKatakana, vbIMEModeKatakanaHalf, vbIMEModeNoControl, vbIMENodeOff, vbIMENodeOn, vbIMENoOp, vbIMEOff, vbIMEOn];
var vba_Enum_vbMsgBoxResult = [vbAbout, vbCancel, vbIgnore, vbNo, vbOK, vbRetry, vbYes]
var vba_Enum_vbMsgBoxStyle = [vbAboortRetryIgnore, vbApplicationModal, vbCritical, vbDefaultButton1, vbDefaultButton2, vbDefaultButton3, vbDefaultButton4, vbExclamation, vbInformation, vbMsgBoxHelpButton, vbMsgBoxRight, vbMsgBoxRtlReading, vbMsgBoxSerForeground, vbOKCancel, vbOKOnly, vbQuestion, vbRetryCancel, vbSystemModal, vbYesNo,vbYesNoCancel];
var vba_Enum_vbQueryClose = [vbAppTaskManager, vbAPPWindows, vbFormCode, vbFormControlMenu, vbFormMDIForm];
var vba_Enum_vbStrConv = [vbFormUnicode, vbHiragana, vbKatakana, vbLowerCase, vbNorrow, vbProperCase, vbUnicode, vbUpperCase, vbWide];
var vba_Enum_vbTriState = [vbFalse, vbTrue, vbUseDefault];
var vba_Enum_vbVarType = [vbArray, vbBoolean, vbByte, vbCurrency, vbDataObject, vbDate, vbDecimal, vbDouble, vbEmpty, vbError, vbInteger, vbLong, vbNull, vbObject, vbSingle, vbUserDifinedType, vbVariant];
オブジェクトライブラリ以外の予約語
VBAを構成する構文解析で登場するキーワードをざっくりと定義します。
もちろん上記のVBAオブジェクトライブラリ定義以外となります。
悪戦苦闘で以下のように定義しました。(最終的には完結予定)
// 予約語
var vba_reserved_word = [
AddressOfAnd, Any, Array, As, Attribute, Append,
Base, Binary, Boolean, ByRef, Byte, ByVal,
Call, Case, Circle, Close, Compare, Const,
Debug, Decimal, Declare, DefBool, DefByte, DefCur,
DefDate, DefDbl, DefDec, DefInt, DefLng, DefLngLng,
DefLngPtr, DefObj, DefSng, DefStr, DefVar, Dim, Do, Double,
Each, Else, ElseIf, Empty, End, EndIf, Enum, Eqv, Erase,
Event, Exit, Explicit,
FALSE, For, Friend, Function,
Get, Global, GoSub, GoTo,
If, Imp, Implements, In, Input, InputB, Integer, Is,
Lbound, Let, Like, LINEINPUT, Lock, Long, LongLong,
LongPtr, Loop, Lset,
Me, Mod,
New, Next, Not, Nothing, Null,
On, Open, Option, Optional, Or, Output,
ParamArray, Preserve, Print, Private, Property, PSet,
Public, Put,
Random, RaiseEvent, ReDim, Rem, Resume, Return, Rset,
Scale, Selec, Set, Shared, Single, Spc, Static, Step, Stop, Sub,
Tab, Then, To, TRUE, Type, TypeOf,
Ubound, Unlock, Until,
Variant, VB_Base, VB_Control, VB_Creatable, VB_Customizable,
VB_Description, VB_Exposed, VB_Ext_KEY, VB_GlobalNameSpace,
VB_HelpID, VB_Invoke_Func, VB_Invoke_Property, VB_Invoke_PropertyPut,
VB_Invoke_PropertyPutRef, VB_MemberFlags, VB_Name, VB_PredeclaredId,
VB_ProcData, VB_TemplateDerived, VB_UserMemId, VB_VarDescription,
VB_VarHelpID, VB_VarMemberFlags, VB_VarProcData, VB_VarUserMemId,
Wend, While, With, WithEvents, Write,
Xor
];
// VBA演算子
var vba_operator = ["+", "-", "*", "/", "\", "^"];
// VBA比較演算子
var vba_comparison_operator = ["<", "<=", ">", ">=", "=", "<>"];
予約語について
VBAで登場する予約語をまとめました。
たぶん抜けや誤字・脱字がありそうです。調整しながら進んでいきます。
最初のExcelと翻訳対象VBAコード
構文解析ロジックを組み立てる上で元になるExcelとVBAのサンプルを用意します。
これを最初にJavaScriptへ翻訳して構文解析ロジックの正規化を図りたいと思います。
問題集を作るExcel
① 元文
問題のテキスト(wikiなどからコピペ)。
穴埋め問題にしたいテキストを赤文字に変更します。
②問題
セルA5に**=AnzColor(A1,3)**を入力します。
※カラーインデックス=3は赤
関数 | 引数 | 機能 |
---|---|---|
AnzColor | セルアドレス、カラーインデックス | 元文の指定したカラー文字を□に置換します |
③解答
セルA8に**=AnsColor(A1,3)**を入力します。
※カラーインデックス=3は赤
関数 | 引数 | 機能 |
---|---|---|
AnsColor | セルアドレス、カラーインデックス | 元文の指定したカラー文字を抽出します |
問題集を作るVBAコード
'
' 特定範囲の文字色を判定し、□に変更して返す
' adrs : Cell
' clr : ColorIndex
'
Function AnzColor(adrs, clr) As String
Dim iLen As Integer
Dim ix As Integer
Dim Buf As String
Sheets("Question").Select
Buf = ""
For Each ad In adrs
iLen = Len(ad)
For ix = 1 To iLen
' 指定した色の場合
If ad.Characters(ix, 1).Font.ColorIndex = clr Then
Buf = Buf & "□"
Else
Buf = Buf & Mid(ad, ix, 1)
End If
Next ix
Next
AnzColor = Buf
End Function
'
' 特定範囲の文字色を判定し、文字色に一致する文字列群を返す
' adrs : Cell
' clr : ColorIndex
'
Function AnsColor(adrs, clr) As String
Dim iLen As Integer
Dim ix As Integer
Dim Buf As String
Dim sw As Boolean
Sheets("Question").Select
Buf = ""
sw = True
For Each ad In adrs
iLen = Len(ad)
For ix = 1 To iLen
' 指定した色の場合
If ad.Characters(ix, 1).Font.ColorIndex = clr Then
Buf = Buf & IIf(sw = False, ",", "") & Mid(ad, ix, 1)
sw = True
Else
sw = False
End If
Next ix
Next
AnsColor = IIf(Left(Buf, 1) = ",", Mid(Buf, 2), Buf)
End Function
まとめ
ばたばたと予約語と翻訳対象のVBAを作成しました。
途中で路線変更しそうな予感です。
このあたりが一番退屈なところかもしれません。
予約語はこんな感じぐらいで認識しましょう。