Converting 400 line VBA function to C++

Pages: 12
If the OP would share his original VBA code, it could probably be rewritten to not only be proper C++ but to be faster, too. For instance the fixed strings could probably be enums, which would compare much faster.

Thanks guys, I finally worked out that OP might stand for Original Poster? Yeah, I could share my original VBA code, and I am sure that enums would be very applicable. These posts aren't long enough, so I would to do it some other way. Is there some way of private messaging? Those who want it let me know.
Hi

You could spread the code over 2 or 3 posts if it is 400 lines. Or provide a link to it's location on GitHub or something similar.

Edit:

Also post your attempt at c++ using the example mbozzi gave earlier.
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <string>
#include <map>
using namespace std;

void collectTerm   (){ cout << "This is collectTerm"    << '\n'; }
void collectString (){ cout << "This is collectString"  << '\n'; }
void collectLabel  (){ cout << "This is collectLabel"   << '\n'; }
void lookOper      (){ cout << "This is lookOper"       << '\n'; }
void collectCommand(){ cout << "This is collectCommand" << '\n'; }
void gotEscape     (){ cout << "This is gotEscape"      << '\n'; }


map<string,void (*)()> M = { { "collectTerm"   , collectTerm    },
                             { "collectString" , collectString  },
                             { "collectLabel"  , collectLabel   },   
                             { "lookOper"      , lookOper       },
                             { "collectCommand", collectCommand },
                             { "gotEscape"     , gotEscape      } };

int main()
{
   for ( string strState : { "collectTerm", "lookOper", "gotEscape", "useless" } )
   {
      auto it = M.find( strState );
      if ( it == M.end() ) cout << "Can't find " << strState << '\n';
      else                 (*it).second();
   }
}


This is collectTerm
This is lookOper
This is gotEscape
Can't find useless





If you need access to lots of variables you might prefer to map to member function pointers of some class in which you store those variables:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <string>
#include <map>
using namespace std;

class State
{
   // Lots of variables
   // ...........
public:
   void collectTerm   (){ cout << "This is collectTerm"    << '\n'; }
   void collectString (){ cout << "This is collectString"  << '\n'; }
   void collectLabel  (){ cout << "This is collectLabel"   << '\n'; }
   void lookOper      (){ cout << "This is lookOper"       << '\n'; }
   void collectCommand(){ cout << "This is collectCommand" << '\n'; }
   void gotEscape     (){ cout << "This is gotEscape"      << '\n'; }
};


map<string,void (State::*)()> M = { { "collectTerm"   , &State::collectTerm    },
                                    { "collectString" , &State::collectString  },
                                    { "collectLabel"  , &State::collectLabel   },
                                    { "lookOper"      , &State::lookOper       },
                                    { "collectCommand", &State::collectCommand },
                                    { "gotEscape"     , &State::gotEscape      } };


int main()
{
   State S;

   for ( string strState : { "collectTerm", "lookOper", "gotEscape", "useless" } )
   {
      auto it = M.find( strState );
      if ( it == M.end() ) cout << "Can't find " << strState << '\n';
      else                 (S.*(*it).second)();
   }
}

Last edited on
I have decided to post a different module which exhibits the same design as the one I was talking about. I would be interested in your suggestions on how to break it up as well as opportunities for use of enums.

Note: The naming standard of variables is the first 3 letters are the type (str for String, int for integer, bln for boolean etc). If these are preceded by m (as in mint) it means the variable is scoped at a higher level.
Things like dEOI, dError and intAskedForDelim are bit settings.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
Sub returnCommandParm(ByVal intAskedForDelim As String)
Dim strState As String, strError As String, strErrorState As String, blnFirstTime As Boolean
Dim strValue As String, strCommandType As String
Dim strQreg As String, blnIsFunction As Boolean, strCommand As String
Const strModule As String = "returnCommandParm"

strState = "beginToken": blnFirstTime = True
Do While strState <> strEndParse
    Call getChar
    If strState = "beginToken" Then
        GoSub beginToken
    ElseIf strState = "collectString" Then
        GoSub collectString
    ElseIf strState = "collectCommand" Then
        GoSub collectCommand
    ElseIf strState = "gotEscape" Then
        GoSub gotEscape
    Else
        Call handleError(strModule, strState, "Unknown state") ' tec019
    End If
    If mintDelimType = dError Then strState = strEndParse
Loop
Exit Sub

beginToken:     ' we have nothing - collect characters or $function; or we have existing string and collect more
    If mintDelimType = dEOI Then ' this picks up the premature EOI
        Call handleError(strModule, strState, "` (end of string) missing") ' tec075
    ElseIf (mintDelimType And intAskedForDelim) <> 0 Then ' this picks up asked for delimiters, push whatever we have so far
        If blnFirstTime Then
            Call pushCode("$PUSH", "", rString)  ' push an empty string
        End If
        strState = strEndParse
    ElseIf mstrChar = "$" Then  ' modifier="$" -> push a null for the function call
        Call pushCode("XPUSH", Null, rDefault)
        strCommand = mstrChar: strState = "collectCommand"   ' and go get the command
    ElseIf mstrChar = "\" Then  ' escape
        strState = "gotEscape"
    Else
        strValue = mstrChar: strState = "collectString"
    End If
Return

collectString:    ' we are building up a string term
    If mintDelimType = dEOI Then ' this picks up the EOI
        Call handleError(strModule, strState, "Unexpected EOI while building string") ' tec060
    ElseIf (mintDelimType And intAskedForDelim) <> 0 Then
        Call pushCode("$PUSH", strValue, rString)
        If Not blnFirstTime Then    ' handle string concatenation
            mintCodeStack = mintCodeStack + 1: codeStack(mintCodeStack, 1) = "$OPER": codeStack(mintCodeStack, 2) = "+"
            mintExecStack = mintExecStack - 1   ' pop off the extra string value
        End If
        strState = strEndParse
    ElseIf mstrChar = "\" Then  ' escape
        strState = "gotEscape"
    ElseIf mstrChar = "$" Then  ' modifier="$" -> push collected string, then a null for the function call
        Call pushCode("$PUSH", strValue, rString)
        If Not blnFirstTime Then
            mintCodeStack = mintCodeStack + 1: codeStack(mintCodeStack, 1) = "$OPER": codeStack(mintCodeStack, 2) = "+"
            mintExecStack = mintExecStack - 1   ' pop off the extra string value
        End If
        blnFirstTime = False
        Call pushCode("XPUSH", Null, rDefault)
        strCommand = mstrChar: strState = "collectCommand"   ' and go get the command
    Else    ' everything else - add to value
        strValue = strValue & mstrChar
    End If
Return

collectCommand: ' string-version
    If mintDelimType = dEOI Then ' this picks up the EOI
        Call handleError(strModule, strState, "Unexpected EOI while building command/function") ' tec026
    ElseIf (mintDelimType And intAskedForDelim) <> 0 Then ' this picks any asked for delimiters
        Call handleError(strModule, strState, "Unexpected character while building command/function") ' tec027
    ElseIf (mintCharType And aCmdChar) Then
        strCommand = strCommand & mstrChar
        strCommandType = commandType(strCommand, strQreg, blnIsFunction)
' commandType {unknown, command, incomplete, exprCommand, exprFunction}
        If strCommandType = rUnknown Then
            strState = strEndParse  ' exit because we have already done our error message
        ElseIf strCommandType = rCommand Then
            Call handleError(strModule, strState, "Command not valid inside parameter") ' tec061
        ElseIf strCommandType = rIncomplete Then
            ' if incomplete just collect more characters
        Else ' must be either exprCommand or exprFunction
            ' now do the expression - which will push the result onto the stack
            If processCommand(strModule, strState, strCommand, strQreg, blnIsFunction) Then
                If Not blnFirstTime Then
                    mintCodeStack = mintCodeStack + 1: codeStack(mintCodeStack, 1) = "$OPER": codeStack(mintCodeStack, 2) = "+"
                    mintExecStack = mintExecStack - 1   ' take 2 strings off stack and replace with 1
                End If
                strState = "begintoken": blnFirstTime = False
            End If
        End If
    Else ' error token not a command
        Call handleError(strModule, strState, "Unexpected character while building command/function")   'tec027
    End If
Return

gotEscape: ' have an escape, see what next character is
    If mintDelimType = dEOI Then ' this picks up the EOI
        Call handleError(strModule, strState, "Unexpected EOI while building string")   ' tec060
    Else    ' all other characters - just add them to the string
        If mstrChar = "t" Then
            strValue = strValue & vbTab
        ElseIf mstrChar = "r" Then
            strValue = strValue & vbCr
        ElseIf mstrChar = "n" Then
            strValue = strValue & vbLf
        Else
            strValue = strValue & mstrChar
        End If
        strState = "collectString"
    End If
Return

End Sub 


Topic archived. No new replies allowed.
Pages: 12