飴屋ぷろじぇくと

 ちょっとカテゴリを分けてみようかなっと。

--.--.--[--] スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

2014.11.08[土] FreeBASICの#Macroをテンプレート的に使ってみるテスト


FreeBASICは#defineや#includeなど、C言語のプリプロセッサ機能を取り込んでいてその殆どすべてが使えるようなんですが、さらにFB独自の拡張として#macro などという #define の複数行版が実装されてます。
FBでテンプレートと言えば、
http://ext.freebasic.net/tutorial/sat-04202013-2014/templates
http://ext.freebasic.net/dev-docs/files/ext/templates-bi.html
こんなのがあるようで、これはこれで力作みたいなんですが、利用者の少ない現状でこんなブラックボックスを紹介しても仕方がありません。ここはもっと中身が判るように、つまり読む人がFreeBASICという言語(本当はそのプリプロセッサですが)で何をしてるのか(何が出来るのか)が読み解けるように、C++のテンプレートのようなものを作って紹介してみようと思います。

定義:
#define Vector(T) T##_Vector

#Macro Declare_Vector(T)
#ifndef ___DECLARE__VECTOR__##T
#define ___DECLARE__VECTOR__##T
Type T##_Vector
    Dim v(Any) As T
    Declare Function Insert(i As Integer, value As T) As Integer
    Declare Function Remove(ByVal i As Integer) As Integer
    Declare Sub Clear()
    Declare Function Find(value As T) As Integer
    Declare Function Back() ByRef As T
    Declare Function Front() ByRef As T
    Declare Sub Push(value As T)
    Declare Sub Pop()
    Declare Operator [](i As Integer) ByRef As T
    Declare Property Size As Integer
    Declare Property Size (n As Integer)
End Type
#endif
#EndMacro

#Macro Implement_Vector(T)
Function T##_Vector.Insert(ByVal i As Integer, value As T) As Integer
    Dim n As Integer = UBound(v)
    Redim Preserve v(n+1)
    If i >= n+1 Then
        i = n+1
        v(i) = value
    Else
        Dim j As Integer
        If i < 0 Then i = 0
        For j = n To i Step -1
            v(j+1) = v(j)
        Next
        v(i) = value
    End If
    Return i
End Function
Function T##_Vector.Remove(ByVal i As Integer) As Integer
    Dim u As Integer = UBound(v)
    if i < 0 Then
        i = 0
    ElseIf i > u Then
        i = u
    End If
    if i >= 0 Then
        u = u - 1
        if u >= 0 Then
            Dim n As Integer
            For n = i To u
                v(n) = v(n+1)
            Next
            Redim Preserve v(u)
        Else
            Erase v
        End IF
    End If
    Return i
End Function
Sub T##_Vector.Clear()
    Erase v
End Sub
Function T##_Vector.Find(value As T) As Integer
    Dim i As Integer
    For i = 0 To UBound(v)
        If value = v(i) Then
            Return i
        End If
    Next
    Return -1
End Function
Function T##_Vector.Back() ByRef As T
    Return v(UBound(v))
End Function
Function T##_Vector.Front() ByRef As T
    Return v(LBound(v))
End Function
Sub T##_Vector.Push(value As T)
    Dim i As Integer = UBound(v) + 1
    Redim Preserve v(i)
    v(i) = value
End Sub
Sub T##_Vector.Pop()
    Dim i As Integer = UBound(v)
    if i > 0 then
        Redim Preserve v(i - 1)
    Else
        Erase v
    End If
End Sub
Operator T##_Vector.[](i As Integer) ByRef As T
    Return v(i)
End Operator
Property T##_Vector.Size As Integer
    Return UBound(v) + 1
End Property
Property T##_Vector.Size (n As Integer)
    If n <= 0 Then
        Erase v
    Else
        Redim Preserve v(n-1)
    End If
End Property
#EndMacro

 お判りと思いますが、これは「ベクタもどき」です。FBの可変長配列のラッパーになってます。なぜ「もどき」かと言えば変態的とも言われているC++のテンプレートの仕様をマクロだけで踏襲するのは不可能でしょうから。なので定義は三つに分けました。

最初の定義は型の名前を作る単純な#defineです。定義中の##は文字列を結合してくれるマクロ内で使う演算子です。
Vector(タイプ名)とやると Vector_タイプ名 に置換されます。
次が#macroの一つ目、Type宣言を生成します。Declare_Vector(タイプ名)とか書きます。
最後に実装部を生成する#macroがあります。
Implement_Vector(タイプ名)で実装部を生成。こちらを分けた理由は、同じ型のVectorを複数のソースで使用している場合に実態がダブってしまわないようにするためです。複数のソースをコンパイルして一つの実行ファイルにまとめる場合、実装部は全体で一つにする必要があります。

こんな風に使います:
'Vector(String)の定義を生成
Declare_Vector(String)
'Vector(String)の実装を生成
Implement_Vector(String)
'変数宣言
Dim v As Vector(String)
v.Push "ABC"
v.Push "DEFG"
v.Push "HIJ"
Print v.Size
Print v[0]
Print v[1]
Print v[2]
Print v.back
Print v.front
Print v.find("DEFG")
Print v.find("XYZ")

各メソッドはC++のstd::vectorを真似てますがイテレータはありません。というかイテレータという仕掛けはBASIC的でない気がするのですが如何でしょうか?

話を戻して、このように
Declare_Vector(Integer)
Implement_Vector(Integer)
とやればIntegerを要素とするVectorも生成できますし、それだけでなく、
Declare_Vector(MyString)
Implement_Vector(MyString)
このようにユーザー定義型でも要素に出来てしまいます。
ただしその型の変数に対して演算子=、演算子Let等が使えるようになっていることが条件ですが。

最後にこのテンプレートの解説:
Insert 指定した場所に要素を挿入します。
Remove 指定した場所の要素を削除します。
Clear 全ての要素を削除します。
Find 指定した値の要素を検索し、そのインデックスを返します
Back 一番後ろの要素を返します
Front 最初の要素を返します
Push 一番後ろに値を追加します
Pop 一番後ろの要素を削除します
Size 要素数を取得/設定します
[] 添字を使ってアクセスします

Comment






(編集・削除用)

Trackback

http://utau2009.blog114.fc2.com/tb.php/28-7662c290

この記事にトラックバック(FC2Blog User)

Copyright © 飴屋/菖蒲

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。