Union as 'own' data-type

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Post Reply
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Union as 'own' data-type

Post by MrSwiss »

In this example a packed *BCD type is created, then used with the associated procedures (to the Union).

*BCD = binary coded decimal (UByte with range: 0 To 99)

BCD_u.bas:

Code: Select all

' BCD_u.bas -- (c) 2019-02-20, MrSwiss
'
' compile: -s console
'

' BCD_u - union start
Union BCD_u                             ' packed BCD union (value range: 00 To 99)
    As UByte    BCD                     ' packed BCD UByte
    Type
        lo : 4 As UByte                 ' low Nibble (4 bits)
        hi : 4 As UByte                 ' high Nibble (4 bits)
    End Type
    Type
        _0 : 1 As UByte                 ' bit values (0 or 1)
        _1 : 1 As UByte
        _2 : 1 As UByte
        _3 : 1 As UByte
        _4 : 1 As UByte
        _5 : 1 As UByte
        _6 : 1 As UByte
        _7 : 1 As UByte
    End Type
    Declare Function set_BCD(ByVal nBCD As UByte) As Boolean            ' setter BCD
    Declare Function get_BCD() As UByte                                 ' getter BCD
    Declare Function get_Nib(ByVal high As Boolean = FALSE) As UByte    ' get nibble
    Declare Function get_Bit(ByVal nbit As UByte = 0) As UByte          ' get bit
    Declare Sub      showBCD()                                          ' print BDC
    Declare Sub      showNib(ByVal high As Boolean = FALSE)             ' print nibble
    Declare Sub      showBit(ByVal nbit As UByte = 0)                   ' print bit
    Declare Operator Let(ByRef rhs As BCD_u)                            ' union to union
    Declare Operator Let(ByVal rhs As UByte)                            ' value to union
End Union

Function BCD_u.set_BCD( _               ' set a new value
    ByVal nBCD  As UByte _              ' new value (mandatory)
    ) As Boolean
    If nBCD > 99 Then Return TRUE       ' ERROR: value 'out of range'!
    This.hi = nBCD \ 10                 ' calc. and set ten's
    This.lo = nBCD Mod 10               ' calc. and set unit's
    Return FALSE                        ' OK
End Function

Function BCD_u.get_BCD() As UByte       ' get current value
    Return This.hi * 10 + This.lo       ' construct return
End Function

Function BCD_u.get_Nib( _               ' get nibble (default: low nibble)
    ByVal high  As Boolean = FALSE _    ' parenthesis are optional if default
    ) As UByte
    If high Then
        Return This.hi * 10             ' construct return (ten's)
    Else
        Return This.lo                  ' direct value (unit's)
    End If
End Function

Function BCD_u.get_Bit( _               ' get bit (default: bit 0)
    ByVal nbit  As UByte = 0 _          ' selector of bit to return
    ) As UByte
    With This
    Select Case As Const nbit
        Case 0 : Return ._0
        Case 1 : Return ._1
        Case 2 : Return ._2
        Case 3 : Return ._3
        Case 4 : Return ._4
        Case 5 : Return ._5
        Case 6 : Return ._6
        Case 7 : Return ._7
    End Select
    End With
End Function

Sub BCD_u.showBCD()                     ' print current BCD value
    Print "BCD value: "; This.hi * 10 + This.lo ' construct print
End Sub

Sub BCD_u.showNib( _                    ' parenthesis are optional _
    ByVal high  As Boolean = FALSE _    ' if default (default: low nibble)
    )
    If high Then
        Print This.hi; " ten's"         ' print direct value
    Else
        Print This.lo; " unit's"        ' print direct value
    End If
End Sub

Sub BCD_u.showBit( _                    ' print selected bit
    ByVal nbit  As UByte = 0 _          ' selector of bit to print _
    )                                   ' (default: bit 0)
    With This
    Select Case As Const nbit
        Case 0 : Print "bit 0: "; ._0
        Case 1 : Print "bit 1: "; ._1
        Case 2 : Print "bit 2: "; ._2
        Case 3 : Print "bit 3: "; ._3
        Case 4 : Print "bit 4: "; ._4
        Case 5 : Print "bit 5: "; ._5
        Case 6 : Print "bit 6: "; ._6
        Case 7 : Print "bit 7: "; ._7
    End Select
    End With
End Sub

Operator BCD_u.Let( _                   ' assign union to union
    ByRef rhs   As BCD_u _
    )  
    This.BCD = rhs.BCD                  ' simply assign
End Operator

Operator BCD_u.Let( _                   ' assign value to union
    ByVal rhs   As UByte _
    )
    If rhs > 99 Then rhs = 0            ' auto correct input (on error)
    This.hi = rhs \ 10                  ' calc. and set ten's
    This.lo = rhs Mod 10                ' calc. and set unit's
End Operator
' BCD_u - union end

' demo code
Dim As BCD_u    u1, u2, u3              ' 3 BCD instances (union)

u2 = 33                                 ' let Operator test (union/value)
u3 = u2                                 ' let Operator test (union/union)

If u1.set_BCD(99) Then                  ' alternative method, using setter
    Print "ERROR: set value > 99"       ' show error
Else
    Print "set value = "; : u1.showBCD  ' show set value (all OK)
End If : Print                          ' add LF

For i As UInteger = 0 To 3              ' loop of low 4 bits
    u1.showBit(i)                       ' show bit
Next
u1.showNib : Print                      ' low nibble | add LF

For i As UInteger = 4 To 7              ' loop of high 4 bits
    u1.showBit(i)
Next
u1.showNib(TRUE) : Print                ' show high nibble

Print "___ u2 ___"
u2.showNib(TRUE) : u2.showNib 
u2.showBCD : Print

u3 = 100                                ' result should be: 0
Print "___ u3 ___"
u3.showNib(TRUE) : u3.showNib
u3.showBCD : Print

Sleep
' ----- EOF -----
Tested: FBC 32 -gen GAS, FBC 64 -gen GCC (version: 1.06.0 official release)
Post Reply