A compact C++ interpreter









C++ By Example

Command Summary


When UCW loads you will be presented with the ;> prompt. You can now type a valid C++ statement, a preprocessor directive like #include, or one of several extra interactive commands which all begin with '#'.   The Windows version allows you to mark output by dragging the mouse, and then ctrl-C or right-click will copy to the clipboard.  It's also possible to use ctrl-V to paste commands into the prompt.


Alternatively, if using Windows, you can download the version of Quincy 2000, which will do these commands for you.

Quit Command: #q, #ql


Close session; #ql in addition writes a unique log file, with a

name based on the time and date.

Load Command: #l <file>


The most important command is #l file which has the same effect

as #include "file", except that the system does some clean-ups if

that module has been previously loaded.  It will remove any macros

that were defined in that source file, clean out typedefs, and

remove any injected namespaces.  So even if the std namespace is

loaded in your interactive session (and this is the default) this

doesn't apply to any #l'd files.


After the first load, #l on its own will reload the last file.

Run Program: #r <file> <command-line arguments>

After a file containing a main() function is loaded, and successfully

compiled, #r will let you run that program with the supplied

arguments.  In UnderC for Windows, the program is run in its own thread and console window,  so you can interactively evaluate variables etc while the program is waiting for input.

Execute shell command: #x <cmd>

For example, #x dir or #x ls -a, depending on your religion.

Load Library command: #lib <dll>, #unload <dll>

After this command, any prototype or class definition is assumed

to be a request for dynamically linking to the library.  This continues until a #lib command without any file is found.


It is easy to import any extern "C" function from a DLL. For example,

all Windows systems have the Microsoft C runtime DLL, MSVCRT40.DLL. To make isalpha() available, one can say:


;> #lib msvcrt40.dll

;> extern "C" int isalpha(char);

;> isalpha('*');

(int) 0

;> #lib


It's important to finish off with a closing #lib, since UC will try to import any  C++ prototype from the current library until then. Please note that #lib on its own does not unload the library; it merely signals the end of a special mode where prototypes are treated differently.


And in Linux, the equivalent is the standard C runtime shared library:

;> #lib libc.so.6

;> extern "C" int isalpha(char);

;> isalpha('*');

(int) 0

;> #lib


You can of course use your own DLLs (they must be extern "C" exports) but remember in Linux to set the LD_LIBRARY_PATH appropriately. The #unload command will release a DLL, so you can rebuilt it without leaving UnderC.  The functions then have to be reloaded as above, so it's useful to put this stuff in header files.


The #lib feature will probably change somewhat; a C purist would prefer a UC-specific #pragma, rather than a new command.


You can now say #pragma dlink libc.so.6 in the above example, (and just #pragma dlink to finish).  The advantage of using a pragma is that C++ compilers will not complain about special pragmas, but #lib is still supported.


There is a special form, #lib $caller, which can be used by the UC DLL/shared library to link to any functions exported by the main program itself.

Setting and Getting the Current Directory: #cd, #pwd

These commands can be used to set and display the current working directory.

Set Options: #opt

These are single-character options with either a '+' or a '-' following them.  For instance, #opt u+ switches on automatic dissembling of the generated pcode, and #opt u- switches this off. The following options are all off by default, but can be useful in debugging.


t  - trace function call stack on crash  

v  - 'verbose'   - if trace is set, will trace ALL function calls.

4 - align to the nearest four-byte in structures

Setting Breakpoints: #b, #gt, #bs, #ff

There are also commands for setting breakpoints, etc, which are chiefly intended for use of any IDE. #b line file will set a breakpoint at that point; #gt works the same way, but is used just to 'go to' a particular line.  The file must be loaded for these commands to have effect.


If the file is recompiled, then the breakpoints can get out of sync. The #bs command is passed a filename, and a list of line numbers, which are interpreted as the new line numbers for each breakpoint. 


When a program has halted, then #r (without any parameters) will continue program execution.


#ff is useful when you are halted at a breakpoint; you can switch to various function frames interactively (works rather like the GDB equivalent;  this is still a new feature so it sometimes interferes with program resumption)

Inspecting and Displaying Variables: #lv, #d, #v, #rm

#lv will display the current set of local variables. #d will display the the specified structure.  For example:


;> string s = "hello dolly";

;> #d s

(unsigned int) m_len = 11

(char*) m_str = "hello dolly"



#v will give information about the specified function or variable. For example,  this shows all members of an overloaded operator.


;> #v operator<<

VAR ostream& substr(ostream&,int) << size 4 offset 9297344

1 ostream& operator<<(ostream&,int)

2 ostream& operator<<(ostream&,unsigned long int)

3 ostream& operator<<(ostream&,bool)

4 ostream& operator<<(ostream&,double)

5 ostream& operator<<(ostream&,float)

6 ostream& operator<<(ostream&,const char*)

7 ostream& operator<<(ostream&,_Endl_&)

8 ostream& operator<<(ostream&,void*)

9 ostream& operator<<(ostream&,char)

10 ostream& operator<<(ostream&,const string&)



#rm x removes the symbol x.  Normally UnderC does not regard redeclaration to be an error.  If you redeclare an array, it will not be moved or reallocated if it was the same size as the last declaration.

Preprocessor Extensions


There are currently only two #pragmas available for UnderC.

 #pragma dlink <dll file name>

This has exactly the same function as #lib, except that it is more C++ friendly (other compilers will ignore it).  Default alignment in structures can be switched between none,4-byte and 8-byte:

 #pragma pack(1)

 #pragma pack(4)

 #pragma pack(8)

Other values are currently ignored. 8-byte alignment is useful when importing data built with the Microsoft compiler, which defaults to putting double values on 8-byte boundaries.


#alias is like #include, except that the macro arguments are assumed to be on one line, separated by space.  Also an #alias macro can itself contain preprocessor statements by using '@'.  Otherwise # has the usual meanings. For example:

;> #alias cd(x) @cd x @pwd

;> cd fred

expands to

 #cd fred


;> #alias sh(x) show(#x);

;> sh tommy

expands to



Built-in Functions

The following library functions are already available:


sin, cos, exp, log, atof, atoi, rand

strcpy, strncpy, strcat, strcmp, strdup, strtok, strstr, strlen,memmove




These are of course not the whole C runtime library, but it's quite easy to add them using the #lib feature as discussed above.  See the <cctype> include file for an example.


You may  find it necessary to put empty stdio.h, etc headers in the

include directory for compatibility with traditional systems. 

An Example Transcript


UnderC Development Project, Vs 0.9.0w

Steve Donovan, 2001

;> // demonstrating std::string

;> string s = "hello dolly";

;> s.substr(0,5);

(string) 'hello'

;> s.substr(s.find("dolly"),5);

(string) 'dolly'

;> s += " you're so swell";

(string&) 'hello dolly you're so swell'

;> s.length();

(int) 27

;> // creating a list of strings...

;> list<string> ls;

instantiated: list<string>

;> ls.push_back(s);

;> ls.push_back("way back when");

;> ls.front();

(string&) 'hello dolly you're so swell'

;> ls.back();

(string&) 'way back when'

;> ls.push_front("singing...");

;> typedef list<string> LS;

;> LS::iterator li;

;> for(li=ls.begin();li!=ls.end();++li)

;>   cout << *li << endl;


hello dolly you're so swell

way back when

;> // demonstrating vectors...

;> vector<int> vi;

instantiated: vector<int>

;> for(int i=0;i<10;i++)

;>   vi.push_back(i);

;> vi[9];

(int&) 9

;> // a useful shortcut!

;> #define FORALL(i,c) \

;>  for(i=c.begin();i!=c.end();++i)

;> vector<int>::iterator ii;

;> int sum = 0;

;> FORALL(ii,vi) sum += *ii;

;> sum;

(int) sum = 45

;> // typing in a function (can be overloaded)

;> int sqr(int i) { return i*i;}

;> sqr(10);

(int) 100

;> double sqr(double x) { return x*x; }

;> sqr(1.2);

(double) 1.44

;> // the function main is special

;> int main() {

;:1} int i,j;

;:1} cin >> i >> j;

;:1} cout << "i+j = " << i+j << endl;

;:1} }

;> #r

10 20

I+j = 30

;> #q                     


You could have executed main() directly, but using #r forces the

function to run in its own thread and window (at least for the Windows version)


The UnderC Development Project, Steve Donovan, 2001