Friday, August 27, 2010

Creating Shared Libraries under MAC OS X

One of my friend who has started to work on a Qt project on MAC OS X ( Snow leopard ) asked me to explain the steps for creating a Shared library in MAC OS X. Here is a sample program which i wrote to explain him the stuff

////////////
// test.cpp
// Source code of a small Shared library
//
//
// Written by Praseed Pai K.T.
// http://praseedp.blogspot.com
//
// At the MAC OS X terminal
// ------------------------
// g++ -c -fPIC test.cpp
// g++ -dynamiclib -o libTest.so test.o
//
// This will produce libTest.so
//
//
//
#include <stdio.h>

extern "C" int Add(int a , int b )
{
return a+b;
}


In GNU Linux , we use -shared as the flag while creating the .so file. In MAC OS X , we need to give -dynamiclib instead.
Also given below is the calling program

////////////////
// caller.cpp
//
// Written by Praseed Pai K.T.
// http://praseedp.blogspot.com
//
//
// At the MAC OS X Terminal
// ------------------------
//
// g++ caller.cpp -o caller.exe ./libTest.so
// ./caller.exe
//
#include <stdio.h>

extern "C" int Add(int a , int b );


int main( int argc , char **argv )
{
printf("The add is %d + %d = %d \n",2,3,Add(2,3));

}


Happy Coding !

Programming vs Software Engineering

I was having a conversation with a budding Programmer. He asked me a question regarding the boredom faced by most IT professionals. I pondered a bit and here was my pitch to him.


Software Engineering is a way of making a living and Programming is an intellectual activity. if you do not treat Programming as an intellectual activity , you will definitely feel bored. In the case of Software Engineering , we need to focus on Shipping the software . Schedules , Deadlines and Compliance dominate there.

Thursday, August 26, 2010

Python 2.x , 3.x and Extension modules

My talk on "Extending and Embedding Python under Windows using C/C++" has been approved by the Pycon india 2010 talks review team. The problem which i faced initially was the ubiquity of Python 2.x applications. Even though , the current stable version is 3.1.2 , it seems not much people are using it.

The problem is as follows. There are subtle but significant changes between 2.x and 3.x extension code. There are minor changes in the language too. At first , i started writing my stuff using Python 3.1.2 and now i have got source modules which can be compiled for Python 3.x and Python 2.x

I am using Visual C/C++ command line compiler to compile and link my extensions. The idea of the talk is to teach !!

Writing some code using C#/.NET as part of my job after a period of one year

Today , i wrote some .net code to upload files using WCF Web service and MTOM. The part of the code might go into the production soon. It was a pleasant feeling to write code for a Commercial application after a long time ( after a gap of more than a year ) using C#/.NET

Friday, August 20, 2010

What is wrong in bowling a no ball ?

The SL cricketer Suraj Ranadiv and Dilshan were under fire for "deliberate" no ball to deny a century to Virender Sehwag. IMHO , they have done the right thing by doing that. Why should one give Psychological advantage to a person from the opposite team ? I think , it is some kind of "chronie" socialism at work in the cricketing circles.

Monday, August 16, 2010

Yantrix Antara - A cross platform ISP system for AT89S5X

Yantrix has released a cross platform in system programmer for AT89S5X. The Desktop part of the project uses
Fox toolkit , Win32 serial API , Linux serial API etc . The source code of the project can be accessed from http://sourceforge.net/p/yantrixantara/home/

Back in the Office after ten days

I was down with the viral fever for most of the last week and it was quite a relief to be back in the office after
a gap of ten days. Did some pre sales activities , some testing and caught up with what happened in my absentia.

Wednesday, August 04, 2010

Lightweight Code Generation under .NET

The following program demonstrates Light Weight Code Generation under .NET

//////////////////////////////////////////////////////////////////////
//
// A Four function calculator which generates .NET IL code on the fly .
//
// using Light Weight Code generation under .NET
//
//
//
// BNF Grammar for Evaluator
//
//
// <expr> ::= <term> | <term> { '+' | '-' } <expr>
//
// <term> ::= <factor> | <factor> { '*' | '/' } <term>
//
// <factor> ::= <TOK_DOUBLE> | ( <expr> ) | { + | - } <factor>
//
//
//
//
//
// Written by
// Praseed Pai K.T.
// http://praseedp.blogspot.com
//
//

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
///////////////////////////////////////////////////////////////////////////////
//
//
// enum TOKEN - Symbolic constants for Lexical Tokens
//
// class Lexer - Lexical Analyzer module. ( proof of concept endeavour )
//
// class CLRParser - A recursive descent parser created to generate IL
// code on the fly.

namespace ExpressionEvaluator
{
////////////////////////////////////////////////
//
// Lexical Tokens
//
//
//
public enum TOKEN
{
ILLEGAL_TOKEN=-1, // Not a Token
TOK_PLUS=1, // '+'
TOK_MUL, // '*'
TOK_DIV, // '/'
TOK_SUB, // '-'
TOK_OPAREN, // '('
TOK_CPAREN, // ')'
TOK_DOUBLE, // '('
TOK_NULL // End of string
}
//////////////////////////////////////////////////////////
//
// A naive Lexical analyzer which looks for operators , Parenthesis
// and number. All numbers are treated as IEEE doubles. Only numbers
// without decimals can be entered. Feel free to modify the code
// to accomodate LONG and Double values
public class Lexer
{
String IExpr; // Expression string
int index ; // index into a character
int length; // Length of the string
double number; // Last grabbed number from the stream
/////////////////////////////////////////////
//
// Ctor
//
//
public Lexer(String Expr)
{
IExpr = Expr;
length = IExpr.Length;
index = 0;
}
/////////////////////////////////////////////////////
// Grab the next token from the stream
//
//
//
//
public TOKEN GetToken()
{
TOKEN tok = TOKEN.ILLEGAL_TOKEN;
////////////////////////////////////////////////////////////
//
// Skip the white space
//
while (index < length &&
(IExpr[index] == ' ' || IExpr[index]== '\t') )
index++;
//////////////////////////////////////////////
//
// End of string ? return NULL;
//
if ( index == length)
return TOKEN.TOK_NULL;
/////////////////////////////////////////////////
//
//
//
switch(IExpr[index])
{
case '+':
tok = TOKEN.TOK_PLUS;
index++;
break;
case '-':
tok = TOKEN.TOK_SUB;
index++;
break;
case '/':
tok = TOKEN.TOK_DIV;
index++;
break;
case '*':
tok = TOKEN.TOK_MUL;
index++;
break;
case '(':
tok = TOKEN.TOK_OPAREN;
index++;
break;
case ')':
tok = TOKEN.TOK_CPAREN;
index++;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{
String str="";
while ( index < length &&
( IExpr[index]== '0' ||
IExpr[index]== '1' ||
IExpr[index]== '2' ||
IExpr[index]== '3' ||
IExpr[index]== '4' ||
IExpr[index]== '5' ||
IExpr[index]== '6' ||
IExpr[index]== '7' ||
IExpr[index] == '8'||
IExpr[index]== '9' ))
{
str += Convert.ToString(IExpr[index]);
index ++;
}
number = Convert.ToDouble(str);
tok = TOKEN.TOK_DOUBLE;
}
break;
default:
Console.WriteLine("Error While Analyzing Tokens");
throw new Exception();
}
return tok;
}


public double GetNumber() { return number; }
}
///////////////////////////////////////////////////////////
//
//
//
//
//
class CLRParser : Lexer
{
TOKEN Current_Token; // Current input token
/////////////////////////////////////////////
// CLR/IL related classes from Reflection.Emit
//
//
ILGenerator ILout;

DynamicMethod myMthdBld;

//////////////////////////////////////////////////
//
// Ctor
//
public CLRParser(String str):base(str)
{
CreateAssemblyOntheFly();
}
/////////////////////////////////////////////////////////////
//
//
//
//
private void CreateAssemblyOntheFly()
{



myMthdBld = new DynamicMethod("Eval",
typeof(double), new Type[] {},typeof(CLRParser) , false);
ILout = myMthdBld.GetILGenerator();

return;
}
//////////////////////////////////////////////
//
//
// Parser Driver
//
//
public double CallExpr()
{
Current_Token= GetToken(); // Grab the First token
///////////////////////////////////////////
// Call the Top level evaluation method Expr
//
Expr();
/////////////////////////////
// Emit Return instruction in the method code stream
//
ILout.Emit(OpCodes.Ret);


//////////////////////////////////////////////////
// Call the method
//
return (double)myMthdBld.Invoke(null,
null);
}
//////////////////////////////////////////////////////////////////////
//
// <expr> ::= <term> | <term> { '+' | '-' } <expr>
//
//
//
public void Expr()
{
TOKEN l_token;
Term();
if ( Current_Token == TOKEN.TOK_PLUS || Current_Token == TOKEN.TOK_SUB )
{
l_token = Current_Token;
Current_Token = GetToken();
Expr();
//////////////////////////////////////////////////
// Emit Add or Sub instruction to the stream
//
ILout.Emit(l_token == TOKEN.TOK_PLUS ? OpCodes.Add : OpCodes.Sub );
}
}
///////////////////////////////////////
//
// <term> ::= <factor> | <factor> { '*' | '/' } <term>
//
//
public void Term()
{
TOKEN l_token;
Factor();
if ( Current_Token == TOKEN.TOK_MUL || Current_Token == TOKEN.TOK_DIV )
{
l_token = Current_Token;
Current_Token = GetToken();
Term();
//////////////////////////////////////////////////
// Emit Mul or Div instruction to the stream
//
ILout.Emit( l_token == TOKEN.TOK_MUL ? OpCodes.Mul:OpCodes.Div);
}
}
//////////////////////////////////////////////////////
//
// <factor> ::= <TOK_DOUBLE> | ( <expr> ) | {+ | - } <factor>
//
//
public void Factor()
{
TOKEN l_token;
if ( Current_Token == TOKEN.TOK_DOUBLE )
{
////////////////////////////////////////////
//
// Load the Data into the CLR stack
//
ILout.Emit(OpCodes.Ldc_R8, GetNumber());
Current_Token = GetToken();
}
else if ( Current_Token == TOKEN.TOK_OPAREN )
{
Current_Token = GetToken();
Expr(); // Recurse
if ( Current_Token != TOKEN.TOK_CPAREN )
{
Console.WriteLine("Missing Closing Parenthesis\n");
throw new Exception();
}
Current_Token = GetToken();
}
else if ( Current_Token == TOKEN.TOK_PLUS || Current_Token == TOKEN.TOK_SUB )
{
l_token = Current_Token;
Current_Token = GetToken();
Factor();
if ( l_token == TOKEN.TOK_SUB )
{
///////////////////////////////
//
// TOP_OF_STACK = -TOP_OF_STACK
ILout.Emit(OpCodes.Neg );
}
}
else
{
Console.WriteLine("Illegal Token");
throw new Exception();
}
}
//////////////////////////////////////////////////////////////////
//
// Entry point for the Test Driver
//
//
//
public static void Main(string[] args)
{
if ( args.Length == 0 || args.Length > 1 )
{
Console.WriteLine("Usage : Expr \"<expr>\" \n");
Console.WriteLine(" eg:- Expr \"2*3+4\" \n");
Console.WriteLine(" Expr \"-2-3\" \n");
return;
}
try {
CLRParser parser = new CLRParser(args[0]);
double nd = parser.CallExpr();
Console.WriteLine("The Evaluated Value is {0} \n",nd );
}
catch(Exception )
{
Console.WriteLine("Error Evaluating Expression\n");
return;
}
}
}

}

A Four Function Calculator which generates IL on the fly

The following program generates IL from arbitary mathematical expressions from the command line

//////////////////////////////////////////////////////////////////////
//
// A Four function calculator which generates .NET IL code on the fly .
//
//
//
//
//
// BNF Grammar for Evaluator
//
//
// <expr> ::= <term> | <term> { '+' | '-' } <expr>
//
// <term> ::= <factor> | <factor> { '*' | '/' } <term>
//
// <factor> ::= <TOK_DOUBLE> | ( <expr> ) | { + | - } <factor>
//
//
//
//
//
// Written by
// Praseed Pai K.T.
// http://praseedp.blogspot.com
//
//

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
///////////////////////////////////////////////////////////////////////////////
//
//
// enum TOKEN - Symbolic constants for Lexical Tokens
//
// class Lexer - Lexical Analyzer module. ( proof of concept endeavour )
//
// class CLRParser - A recursive descent parser created to generate IL
// code on the fly.

namespace ExpressionEvaluator
{
////////////////////////////////////////////////
//
// Lexical Tokens
//
//
//
public enum TOKEN
{
ILLEGAL_TOKEN=-1, // Not a Token
TOK_PLUS=1, // '+'
TOK_MUL, // '*'
TOK_DIV, // '/'
TOK_SUB, // '-'
TOK_OPAREN, // '('
TOK_CPAREN, // ')'
TOK_DOUBLE, // '('
TOK_NULL // End of string
}
//////////////////////////////////////////////////////////
//
// A naive Lexical analyzer which looks for operators , Parenthesis
// and number. All numbers are treated as IEEE doubles. Only numbers
// without decimals can be entered. Feel free to modify the code
// to accomodate LONG and Double values
public class Lexer
{
String IExpr; // Expression string
int index ; // index into a character
int length; // Length of the string
double number; // Last grabbed number from the stream
/////////////////////////////////////////////
//
// Ctor
//
//
public Lexer(String Expr)
{
IExpr = Expr;
length = IExpr.Length;
index = 0;
}
/////////////////////////////////////////////////////
// Grab the next token from the stream
//
//
//
//
public TOKEN GetToken()
{
TOKEN tok = TOKEN.ILLEGAL_TOKEN;
////////////////////////////////////////////////////////////
//
// Skip the white space
//
while (index < length &&
(IExpr[index] == ' ' || IExpr[index]== '\t') )
index++;
//////////////////////////////////////////////
//
// End of string ? return NULL;
//
if ( index == length)
return TOKEN.TOK_NULL;
/////////////////////////////////////////////////
//
//
//
switch(IExpr[index])
{
case '+':
tok = TOKEN.TOK_PLUS;
index++;
break;
case '-':
tok = TOKEN.TOK_SUB;
index++;
break;
case '/':
tok = TOKEN.TOK_DIV;
index++;
break;
case '*':
tok = TOKEN.TOK_MUL;
index++;
break;
case '(':
tok = TOKEN.TOK_OPAREN;
index++;
break;
case ')':
tok = TOKEN.TOK_CPAREN;
index++;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{
String str="";
while ( index < length &&
( IExpr[index]== '0' ||
IExpr[index]== '1' ||
IExpr[index]== '2' ||
IExpr[index]== '3' ||
IExpr[index]== '4' ||
IExpr[index]== '5' ||
IExpr[index]== '6' ||
IExpr[index]== '7' ||
IExpr[index] == '8'||
IExpr[index]== '9' ))
{
str += Convert.ToString(IExpr[index]);
index ++;
}
number = Convert.ToDouble(str);
tok = TOKEN.TOK_DOUBLE;
}
break;
default:
Console.WriteLine("Error While Analyzing Tokens");
throw new Exception();
}
return tok;
}


public double GetNumber() { return number; }
}
///////////////////////////////////////////////////////////
//
//
//
//
//
class CLRParser : Lexer
{
TOKEN Current_Token; // Current input token
/////////////////////////////////////////////
// CLR/IL related classes from Reflection.Emit
//
//
ILGenerator ILout;
TypeBuilder myTypeBld ;
MethodBuilder myMthdBld;
AssemblyBuilder myAsmBuilder;
AppDomain myDomain;
ModuleBuilder myModule;
AssemblyName asmName;
//////////////////////////////////////////////////
//
// Ctor
//
public CLRParser(String str):base(str)
{
CreateAssemblyOntheFly();
}
/////////////////////////////////////////////////////////////
//
//
//
//
private void CreateAssemblyOntheFly()
{
myDomain = Thread.GetDomain(); // Get current App Domain
//////////////////////////////////////////////
// Define Assembly related attributes and module related
// info
asmName = new AssemblyName();
asmName.Name = "DynamicAssembly1";
myAsmBuilder = myDomain.DefineDynamicAssembly(
asmName,
AssemblyBuilderAccess.Run);
myModule = myAsmBuilder.DefineDynamicModule("DynamicModule1");
/////////////////////////////////////////////////////////////////////
//
// Create a class my the name MyDynamicType with a static method
// Eval
//
//
myTypeBld = myModule.DefineType("MyDynamicType",
TypeAttributes.Public);
myMthdBld = myTypeBld.DefineMethod(
"Eval",
MethodAttributes.Public |
MethodAttributes.Static,
typeof(double), // returns a double value
null);
/////////////////////////////////////////////////////
//
// Retrieve CodeGenerator handle
//
ILout = myMthdBld.GetILGenerator();
return;
}
//////////////////////////////////////////////
//
//
// Parser Driver
//
//
public double CallExpr()
{
Current_Token= GetToken(); // Grab the First token
///////////////////////////////////////////
// Call the Top level evaluation method Expr
//
Expr();
/////////////////////////////
// Emit Return instruction in the method code stream
//
ILout.Emit(OpCodes.Ret);
///////////////////////////////////////////////////
// Create a Type (some sort of intermediate compilation
//
// going on inside ? )
Type myType = myTypeBld.CreateType();
//////////////////////////////////////////////////
// Call the method
//
return (double)myType.InvokeMember("Eval",
BindingFlags.InvokeMethod |
BindingFlags.Public |
BindingFlags.Static,
null,
null,
null);
}
//////////////////////////////////////////////////////////////////////
//
// <expr> ::= <term> | <term> { '+' | '-' } <expr>
//
//
//
public void Expr()
{
TOKEN l_token;
Term();
if ( Current_Token == TOKEN.TOK_PLUS || Current_Token == TOKEN.TOK_SUB )
{
l_token = Current_Token;
Current_Token = GetToken();
Expr();
//////////////////////////////////////////////////
// Emit Add or Sub instruction to the stream
//
ILout.Emit(l_token == TOKEN.TOK_PLUS ? OpCodes.Add : OpCodes.Sub );
}
}
///////////////////////////////////////
//
// <term> ::= <factor> | <factor> { '*' | '/' } <term>
//
//
public void Term()
{
TOKEN l_token;
Factor();
if ( Current_Token == TOKEN.TOK_MUL || Current_Token == TOKEN.TOK_DIV )
{
l_token = Current_Token;
Current_Token = GetToken();
Term();
//////////////////////////////////////////////////
// Emit Mul or Div instruction to the stream
//
ILout.Emit( l_token == TOKEN.TOK_MUL ? OpCodes.Mul:OpCodes.Div);
}
}
//////////////////////////////////////////////////////
//
// <factor> ::= <TOK_DOUBLE> | ( <expr> ) | {+ | - } <factor>
//
//
public void Factor()
{
TOKEN l_token;
if ( Current_Token == TOKEN.TOK_DOUBLE )
{
////////////////////////////////////////////
//
// Load the Data into the CLR stack
//
ILout.Emit(OpCodes.Ldc_R8, GetNumber());
Current_Token = GetToken();
}
else if ( Current_Token == TOKEN.TOK_OPAREN )
{
Current_Token = GetToken();
Expr(); // Recurse
if ( Current_Token != TOKEN.TOK_CPAREN )
{
Console.WriteLine("Missing Closing Parenthesis\n");
throw new Exception();
}
Current_Token = GetToken();
}
else if ( Current_Token == TOKEN.TOK_PLUS || Current_Token == TOKEN.TOK_SUB )
{
l_token = Current_Token;
Current_Token = GetToken();
Factor();
if ( l_token == TOKEN.TOK_SUB )
{
///////////////////////////////
//
// TOP_OF_STACK = -TOP_OF_STACK
ILout.Emit(OpCodes.Neg );
}
}
else
{
Console.WriteLine("Illegal Token");
throw new Exception();
}
}
//////////////////////////////////////////////////////////////////
//
// Entry point for the Test Driver
//
//
//
public static void Main(string[] args)
{
if ( args.Length == 0 || args.Length > 1 )
{
Console.WriteLine("Usage : Expr \"<expr>\" \n");
Console.WriteLine(" eg:- Expr \"2*3+4\" \n");
Console.WriteLine(" Expr \"-2-3\" \n");
return;
}
try {
CLRParser parser = new CLRParser(args[0]);
double nd = parser.CallExpr();
Console.WriteLine("The Evaluated Value is {0} \n",nd );
}
catch(Exception )
{
Console.WriteLine("Error Evaluating Expression\n");
return;
}
}
}

}

Patching Instruction stream under Visual C++

The following program demonstrates the injection of data into an instruction stream
to patch it.


/////////////////////////////////
//
// A Simple X86 based C/C++ program which
// injects two long values into the instruction stream
//
//
// Written by Praseed Pai K.T.
// http://praseedp.blogspot.com
//
//


#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

char addfunc[] = { 0xB8,0x0,0x0,0x0,0x0 ,
0x05, 0x0,0x0,0x0,0x0,
0xC3 };



typedef long (*BIN_FUNC)( );

int main( int argc , char **argv )
{

DWORD oldprotect ;
long a = 4;
long b = 6;
char *code = ( char *)malloc(128);
memcpy(code,addfunc,sizeof(addfunc));
memcpy(code+1,&a,sizeof(long));
memcpy(code+6,&b,sizeof(long));
VirtualProtect(code, 128 , PAGE_EXECUTE, &oldprotect);
BIN_FUNC func = (BIN_FUNC)((void *)code);
FlushInstructionCache(GetCurrentProcess(),0,0);
long c = (*func)();
VirtualProtect(code, 128, oldprotect, &oldprotect);
free(code);
printf("%d\n",c );


}

Dynamic Compilation using Visual C++ under Windows 32

Here is the source code of a small expression evaluator which generates machine code on the fly .

/////////////////////////////
//
// An Expression Evaluator which generates Native code
// on the fly - 32 bit x86
//
// Written by Praseed Pai K.T.
// http://praseedp.blogspot.com
//
//
//
#include <windows.h>
#include <stdio.h>
#include <process.h>
#include <io.h>
#include <math.h>

#include <string>
#include <vector>
#include <list>
#include <map>

using namespace std ;

enum SYMB_KIND { constant , variable };
enum SYMB_TYPE { long_type , double_type , bool_type ,unspecified_type };
enum SYMB_FORM { s_atomic , s_array };

typedef struct
{

char SymbolName[128];
SYMB_KIND smb_kind;
SYMB_TYPE smb_type;
SYMB_FORM smb_form;

union
{

long offset_from_EBP;

}ADDRESS;

}SYMBOL_INFO;

class SymbolTableManager
{

map<string,SYMBOL_INFO > val;
int LabelIndexValue ;

public:

SymbolTableManager();
~SymbolTableManager();
BOOL AddSymbol( SYMBOL_INFO *new_sym );
SYMBOL_INFO * LookupSymbol(char *Name);
long GetSymbolCount();

};


SymbolTableManager::SymbolTableManager()
{
LabelIndexValue = 900;
};

SymbolTableManager::~SymbolTableManager()
{


}



BOOL SymbolTableManager::AddSymbol( SYMBOL_INFO *new_sym )
{
new_sym->ADDRESS.offset_from_EBP = GetSymbolCount();
val.insert( pair<const string , SYMBOL_INFO>(
new_sym->SymbolName , *new_sym ) );


return TRUE;

}


SYMBOL_INFO * SymbolTableManager::LookupSymbol(char *Name)
{

map<string,SYMBOL_INFO >::iterator i;

return ( ( i = val.find( Name ) ) != val.end() ) ?
reinterpret_cast<SYMBOL_INFO *> (&((*i).second)) :
reinterpret_cast<SYMBOL_INFO *> (NULL);



}


long SymbolTableManager::GetSymbolCount()
{
return val.size();
}




typedef double (*CompiledCode)();
unsigned char *Code;
int ip;


void ParseDoubleDeclaration();
void ParseSetStatement();
void ParseReturnStatement();



enum X86_GEN_REG32
{
REG32_INV = -1, // Invalid Register
REG32_EAX = 0,
REG32_ECX = 1,
REG32_EDX = 2,
REG32_EBX = 3,
REG32_ESP = 4,
REG32_EBP = 5,
REG32_ESI = 6,
REG32_EDI = 7
};


///////////////////////////////////////////
//
//
//
//
//
//
//

struct reg_names32{
char name[10];
X86_GEN_REG32 re;
}REGNAMES[] =
{ {"EAX",REG32_EAX },
{"ECX",REG32_ECX },
{"EDX",REG32_EDX },
{"EBX",REG32_EBX },
{"ESP",REG32_ESP },
{"EBP",REG32_EBP },
{"ESI",REG32_ESI },
{"EDI",REG32_EDI }
};




int FindOrdinal(char *regname )
{

X86_GEN_REG32 temp_value = REG32_INV;
for(int i=0;i< 8; ++i )
{
if ( stricmp(REGNAMES[i].name,regname ) == 0 )
{
temp_value = REGNAMES[i].re;
break;
}

}

if ( temp_value == REG32_INV )
{
fprintf(stdout,"Invalid Register\n");
exit(0);
}

return (int)temp_value;



}



void X86_PUSH_REG32(char *RegName )
{

Code[ip++]=(char)(0x50 + (long ) FindOrdinal(RegName));

}



void X86_POP_REG32(char *RegName )
{

Code[ip++]=(char)(0x58 + (long ) FindOrdinal(RegName));

}


void X86_PUSH_VALUE32(long value)
{

Code[ip++]=0x68;
*((long *)(Code + ip)) = value;
ip+=4;

}


void X86_MOV_REG32_VALUE32( char *RegName,long value )
{
Code[ip++] = 0xB8 + (int)FindOrdinal(RegName);
*((long *)(Code + ip)) = value;
ip+=4;

}



void X86_MOV_REG32_REG32(char *RegOne,char *RegTwo )
{
long rone = FindOrdinal(RegOne);
long rtwo = FindOrdinal(RegTwo);

Code[ip++] = 0x8B;
Code[ip++]= 0xC0 | rone<<3 | rtwo;


}


void X86_ADD_REG32_VALUE32(char *RegName , long value32 )
{
long reg = FindOrdinal(RegName);

Code[ip++]= 0x81;
Code[ip++]= 0xC0 + (reg&0x7);
*((long *)(Code + ip)) = value32;
ip+=4;

}

void X86_SUB_REG32_VALUE32(char *RegName , long value32 )
{
long reg = FindOrdinal(RegName);

Code[ip++]= 0x81;
Code[ip++]= 0xC0 + (5 << 3 ) + (reg&0x7);
*((long *)(Code + ip)) = value32;
ip+=4;

}



void X86_MOV_PTRREG32_REG32( char *RegOne,char *RegTwo )
{
long reg01 = FindOrdinal(RegOne);
long reg02 = FindOrdinal(RegTwo);

///////////////////////////
//
// OpCode for Move
//
Code[ip++] = 0x89;

//////////////////////////////
//
// MOD REG R/M BYTE
// MOD := 00b
// REG := Ordinal of Source Register (0-7)
// R/M has to be 100b to indicate next byte is SIB

Code[ip++] = ( (reg02&0x7) << 3 ) | 0x4;

//////////////////////////////////////
// SIB Byte
//
// Scale := 00b ie 1
// Index := 100b Ie no index
// BASE := Register number

Code[ip++] = (4 << 3 ) | reg01 ;



}

void X86_MOV_PTRREG32PLUSOFFSET_REG32( char *RegOne,long offset , char *RegTwo )
{
long reg01 = FindOrdinal(RegOne);
long reg02 = FindOrdinal(RegTwo);
long mod =0;

///////////////////////////
//
// OpCode for Move
//
Code[ip++] = 0x89;


////////////////////////////////////////////////////
//
//
//

mod = (offset == 0 ) ? 0x0 : (offset >=-127 && offset < 255 ) ? 0x1 : 0x2;





//////////////////////////////
//
// MOD REG R/M BYTE
// MOD := 00b
// REG := Ordinal of Source Register (0-7)
// R/M has to be 100b to indicate next byte is SIB

Code[ip++] = ((mod << 6 ) | (reg02&0x7) << 3 ) | 0x4;

//////////////////////////////////////
// SIB Byte
//
// Scale := 00b ie 1
// Index := 100b Ie no index
// BASE := Register number

Code[ip++] = (4 << 3 ) | reg01 ;

if ( mod == 0x1 ) {
Code[ip++] = offset;
}
else if (mod == 0x2 ) {

*((long *)(Code + ip)) = offset;
ip+=4;
}


}



void X86_CDQ()
{
Code[ip++]= 0x99;

}


void X86_IMUL_REG32_PTRREG32PLUSOFFSET(char *RegOne,char *RegTwo,long offset)
{
long reg01 = FindOrdinal(RegOne);
long reg02 = FindOrdinal(RegTwo);
long mod =0;

Code[ip++] = 0x0F;
Code[ip++] = 0xAF;

mod = (offset == 0 ) ? 0x0 : (offset >=-127 && offset < 255 ) ? 0x1 : 0x2;

//////////////////////////////
//
// MOD REG R/M BYTE
// MOD := 00b
// REG := Ordinal of Source Register (0-7)
// R/M has to be 100b to indicate next byte is SIB

Code[ip++] = ((mod << 6 ) | (reg01&0x7) << 3 ) | 0x4;

//////////////////////////////////////
// SIB Byte
//
// Scale := 00b ie 1
// Index := 100b Ie no index
// BASE := Register number

Code[ip++] = (4 << 3 ) | reg02 ;

if ( mod == 0x1 ) {
Code[ip++] = offset;
}
else if (mod == 0x2 ) {

*((long *)(Code + ip)) = offset;
ip+=4;

}



}


void X86_IDIV_REG32(char *RegOne)
{

Code[ip++] = 0xF7;
Code[ip++] = 248 + (long)FindOrdinal(RegOne);

}

void X86_ADD_PTRREG32PLUSOFFSET_REG32( char *RegOne,long offset , char *RegTwo )
{
long reg01 = FindOrdinal(RegOne);
long reg02 = FindOrdinal(RegTwo);
long mod =0;

///////////////////////////
//
// OpCode for add
//

Code[ip++] = 0x1;

////////////////////////////////////////////////////
//
//
//

mod = (offset == 0 ) ? 0x0 : (offset >=-127 && offset < 255 ) ? 0x1 : 0x2;





//////////////////////////////
//
// MOD REG R/M BYTE
// MOD := 00b
// REG := Ordinal of Source Register (0-7)
// R/M has to be 100b to indicate next byte is SIB

Code[ip++] = ((mod << 6 ) | (reg02&0x7) << 3 ) | 0x4;

//////////////////////////////////////
// SIB Byte
//
// Scale := 00b ie 1
// Index := 100b Ie no index
// BASE := Register number

Code[ip++] = (4 << 3 ) | reg01 ;

if ( mod == 0x1 ) {
Code[ip++] = offset;
}
else if (mod == 0x2 ) {

*((long *)(Code + ip)) = offset;
ip+=4;
}




}


void X86_MOV_REG32_PTRREG32PLUSOFFSET(char *RegOne,char *RegTwo,long offset )
{
long reg01 = FindOrdinal(RegOne);
long reg02 = FindOrdinal(RegTwo);
long mod =0;

Code[ip++] = 0x8B;


mod = (offset == 0 ) ? 0x0 : (offset >=-127 && offset < 255 ) ? 0x1 : 0x2;

//////////////////////////////
//
// MOD REG R/M BYTE
// MOD := 00b
// REG := Ordinal of Source Register (0-7)
// R/M has to be 100b to indicate next byte is SIB

Code[ip++] = ((mod << 6 ) | (reg01&0x7) << 3 ) | 0x4;

//////////////////////////////////////
// SIB Byte
//
// Scale := 00b ie 1
// Index := 100b Ie no index
// BASE := Register number

Code[ip++] = (4 << 3 ) | reg02 ;

if ( mod == 0x1 ) {
Code[ip++] = offset;
}
else if (mod == 0x2 ) {

*((long *)(Code + ip)) = offset;
ip+=4;
}



}



void X86_NEG_REG32(char *RegOne)
{
Code[ip++]=0xF7;
Code[ip++]= 0xD8 + (long)FindOrdinal(RegOne);

}


void X86_PUSH_EBP()
{
Code[ip++] = 0x55;

}

void X86_MOV_EBP_ESP()
{

Code[ip++]= 0x8B;
Code[ip++]= 0xEC;

}

void X86_MOV_ESP_EBP()
{

Code[ip++]=0x8B;
Code[ip++]=0xE5;

}


void X86_POP_EBP()
{

Code[ip++] = 0x5D;
}

void X86_RET_EAX()
{
Code[ip++] = 0xC3;

}


void X86_XOR_EAX_EAX()
{
Code[ip++] = 0x33;
Code[ip++] = 0xC0;
}

void X86_PUSH_EAX()
{
Code[ip++]= 0x50;

}

void X86_PUSH_ECX()
{

Code[ip++]= 0x51;

}


void X86_NOP()
{

Code[ip++] = 0x90;

}



///////////////////////////////////////////////////////////
//
//
//
//
//
//
//


void X87_FLD_REAL64PLUSOFFSET(char *RegOne,long offset)
{

long reg01 = FindOrdinal(RegOne);
long mod =0;

Code[ip++] = 0xDD;

mod = (offset == 0 ) ? 0x0 : (offset >=-127 && offset < 255 ) ? 0x1 : 0x2;

//////////////////////////////
//
// MOD REG R/M BYTE
// MOD := 00b
// REG := Ordinal of Source Register (0-7)
// R/M has to be 100b to indicate next byte is SIB

Code[ip++] = ((mod << 6 ) | 0x0 << 3 ) | 0x4;

//////////////////////////////////////
// SIB Byte
//
// Scale := 00b ie 1
// Index := 100b Ie no index
// BASE := Register number

Code[ip++] = (4 << 3 ) | reg01 ;

if ( mod == 0x1 ) {
Code[ip++] = offset;
}
else if (mod == 0x2 ) {

*((long *)(Code + ip)) = offset;
ip+=4;
}


}


void X87_FSTP_REAL64PLUSOFFSET(char *RegOne,long offset)
{
long reg01 = FindOrdinal(RegOne);
long mod =0;

Code[ip++] = 0xDD;

mod = (offset == 0 ) ? 0x0 : (offset >=-127 && offset < 255 ) ? 0x1 : 0x2;

//////////////////////////////
//
// MOD REG R/M BYTE
// MOD := 00b
// REG := Ordinal of Source Register (0-7)
// R/M has to be 100b to indicate next byte is SIB

Code[ip++] = ((mod << 6 ) | 0x3 << 3 ) | 0x4;

//////////////////////////////////////
// SIB Byte
//
// Scale := 00b ie 1
// Index := 100b Ie no index
// BASE := Register number

Code[ip++] = (4 << 3 ) | reg01 ;

if ( mod == 0x1 ) {
Code[ip++] = offset;
}
else if (mod == 0x2 ) {

*((long *)(Code + ip)) = offset;
ip+=4;
}

}

void X87_FADD_REAL64PLUSOFFSET(char *RegOne,long offset)
{
long reg01 = FindOrdinal(RegOne);
long mod =0;

Code[ip++] = 0xDC;

mod = (offset == 0 ) ? 0x0 : (offset >=-127 && offset < 255 ) ? 0x1 : 0x2;

//////////////////////////////
//
// MOD REG R/M BYTE
// MOD := 00b
// REG := Ordinal of Source Register (0-7)
// R/M has to be 100b to indicate next byte is SIB

Code[ip++] = ((mod << 6 ) | 0x0 << 3 ) | 0x4;

//////////////////////////////////////
// SIB Byte
//
// Scale := 00b ie 1
// Index := 100b Ie no index
// BASE := Register number

Code[ip++] = (4 << 3 ) | reg01 ;

if ( mod == 0x1 ) {
Code[ip++] = offset;
}
else if (mod == 0x2 ) {

*((long *)(Code + ip)) = offset;
ip+=4;
}

}


void X87_FSUB_REAL64PLUSOFFSET(char *RegOne,long offset)
{
long reg01 = FindOrdinal(RegOne);
long mod =0;

Code[ip++] = 0xDC;

mod = (offset == 0 ) ? 0x0 : (offset >=-127 && offset < 255 ) ? 0x1 : 0x2;

//////////////////////////////
//
// MOD REG R/M BYTE
// MOD := 00b
// REG := Ordinal of Source Register (0-7)
// R/M has to be 100b to indicate next byte is SIB

Code[ip++] = ((mod << 6 ) | 0x4 << 3 ) | 0x4;

//////////////////////////////////////
// SIB Byte
//
// Scale := 00b ie 1
// Index := 100b Ie no index
// BASE := Register number

Code[ip++] = (4 << 3 ) | reg01 ;

if ( mod == 0x1 ) {
Code[ip++] = offset;
}
else if (mod == 0x2 ) {

*((long *)(Code + ip)) = offset;
ip+=4;
}

}


void X87_FMUL_REAL64PLUSOFFSET(char *RegOne,long offset)
{
long reg01 = FindOrdinal(RegOne);
long mod =0;

Code[ip++] = 0xDC;

mod = (offset == 0 ) ? 0x0 : (offset >=-127 && offset < 255 ) ? 0x1 : 0x2;

//////////////////////////////
//
// MOD REG R/M BYTE
// MOD := 00b
// REG := Ordinal of Source Register (0-7)
// R/M has to be 100b to indicate next byte is SIB

Code[ip++] = ((mod << 6 ) | 0x1 << 3 ) | 0x4;

//////////////////////////////////////
// SIB Byte
//
// Scale := 00b ie 1
// Index := 100b Ie no index
// BASE := Register number

Code[ip++] = (4 << 3 ) | reg01 ;

if ( mod == 0x1 ) {
Code[ip++] = offset;
}
else if (mod == 0x2 ) {

*((long *)(Code + ip)) = offset;
ip+=4;
}

}


void X87_FDIV_REAL64PLUSOFFSET(char *RegOne,long offset)
{
long reg01 = FindOrdinal(RegOne);
long mod =0;

Code[ip++] = 0xDC;

mod = (offset == 0 ) ? 0x0 : (offset >=-127 && offset < 255 ) ? 0x1 : 0x2;

//////////////////////////////
//
// MOD REG R/M BYTE
// MOD := 00b
// REG := Ordinal of Source Register (0-7)
// R/M has to be 100b to indicate next byte is SIB

Code[ip++] = ((mod << 6 ) | 0x6 << 3 ) | 0x4;

//////////////////////////////////////
// SIB Byte
//
// Scale := 00b ie 1
// Index := 100b Ie no index
// BASE := Register number

Code[ip++] = (4 << 3 ) | reg01 ;

if ( mod == 0x1 ) {
Code[ip++] = offset;
}
else if (mod == 0x2 ) {

*((long *)(Code + ip)) = offset;
ip+=4;
}


}


///////////////////////////////////////////////////////////
//
//
//
//
//
//
//


void X87_FLD_REAL64PLUSOFFSET_EBP(char *RegOne,long offset)
{

long reg01 = FindOrdinal(RegOne);
long mod =0;

Code[ip++] = 0xDD;

mod = (offset >=-127 && offset < 255 ) ? 0x1 : 0x2;

//////////////////////////////
//
// MOD REG R/M BYTE
// MOD := 00b
// REG := Ordinal of Source Register (0-7)
// R/M has to be 100b to indicate next byte is SIB

Code[ip++] = ((mod << 6 ) | 0x0 << 3 ) | 0x5;

//////////////////////////////////////
// SIB Byte
//
// Scale := 00b ie 1
// Index := 100b Ie no index
// BASE := Register number



if ( mod == 0x1 ) {
Code[ip++] = offset;
}
else if (mod == 0x2 ) {

*((long *)(Code + ip)) = offset;
ip+=4;
}


}

void X87_FSTP_REAL64PLUSOFFSET_EBP(char *RegOne,long offset)
{
long reg01 = FindOrdinal(RegOne);
long mod =0;

Code[ip++] = 0xDD;

mod = (offset >=-127 && offset < 255 ) ? 0x1 : 0x2;

//////////////////////////////
//
// MOD REG R/M BYTE
// MOD := 00b
// REG := Ordinal of Source Register (0-7)
// R/M has to be 100b to indicate next byte is SIB

Code[ip++] = ((mod << 6 ) | 0x3 << 3 ) | 0x5;

//////////////////////////////////////
// SIB Byte
//
// Scale := 00b ie 1
// Index := 100b Ie no index
// BASE := Register number



if ( mod == 0x1 ) {
Code[ip++] = offset;
}
else if (mod == 0x2 ) {

*((long *)(Code + ip)) = offset;
ip+=4;
}

}

void X87_FSIN()
{
Code[ip++]=0xD9;
Code[ip++]=0xFE;

}

void X87_FCOS()
{
Code[ip++]=0xD9;
Code[ip++]=0xFF;

}





void term();
void factor();
void expr_prime();

//////////////////////////////////////////////
//
//
//
//
//
long FloatValueasLong(float x)
{
return (*(long * )(void *)&x);

}

long HIGH_DWORD_DOUBLE( double d )
{
double *temp = (double *) &d;

long *lng = (long *)((void *) temp);
return lng[1];
}

long LOW_DWORD_DOUBLE( double d )
{
double *temp = (double *) &d;

long *lng = (long *)((void *) temp);
return lng[0];
}




////////////////////////////
//
//
//

enum TOK_APP
{

TOK_ILLEGAL = -1,
TOK_NULL_VALUE = 0,
TOK_MUL = 1 ,
TOK_DIV,
TOK_ADD,
TOK_SUB,
TOK_EOS,
TOK_FLOAT,
TOK_LONG,
TOK_DOUBLE,
TOK_OPAREN,
TOK_CPAREN,
TOK_DT_LONG,
TOK_DT_DOUBLE,
TOK_DT_FLOAT,
TOK_SEMICOLON,
TOK_UNQUOTED_STRING,
TOK_COMMA,
TOK_EQUAL,
TOK_SET,
TOK_RETURN ,
TOK_FUNC_START,
TOK_SIN,
TOK_COS,
TOK_TAN,
TOK_ABS,
TOK_PI,
TOK_ASIN,
TOK_ACOS,
TOK_ATAN,
TOK_EXP,
TOK_LOG,
TOK_FUNC_END
};

struct CURR_VALUE
{
TOK_APP tk;
double x;
char String[100];
};



void Push(char *reg)
{

// fprintf(stdout, "push %s\n",reg );
X86_PUSH_REG32(reg);
}

void Push(long x )
{
//fprintf(stdout,"MOV EAX ,%d\n push EAX\n" , x );
X86_PUSH_VALUE32(x);

}

void Push(float x )
{

// fprintf(stdout,"MOV EAX,%d\n PUSH EAX\n",FloatValueasLong(x));

X86_PUSH_VALUE32(FloatValueasLong(x));


}

void Push(double x )
{
// fprintf(stdout,"MOV EAX,%d\n PUSH EAX\n",HIGH_DWORD_DOUBLE(x));
// fprintf(stdout,"MOV EAX,%d\n PUSH EAX\n",LOW_DWORD_DOUBLE(x));

X86_PUSH_VALUE32(HIGH_DWORD_DOUBLE(x));
X86_PUSH_VALUE32(LOW_DWORD_DOUBLE(x));


}

void Pop(char *reg)
{
// fprintf(stdout, "pop %s\n",reg );

X86_POP_REG32(reg);

}




void Mul()
{

////////////////////////////////////////////////////
// fprintf(stdout," pop eax \n");
//

Pop("EAX");

/////////////////////////////////////////////////////
// fprintf(stdout," imul eax, [esp]\n");
//
//

X86_IMUL_REG32_PTRREG32PLUSOFFSET("EAX","ESP",0);

/////////////////////////////////////////////////////////
// fprintf(stdout," mov [esp], eax\n" );

X86_MOV_PTRREG32_REG32("ESP","EAX");
}


void MulF()
{
//////////////////////////////////////////////
//fprintf(stdout," fld QWORD [esp] \n");
//
//

X87_FLD_REAL64PLUSOFFSET("ESP",0);



// fprintf(stdout," fmul QWORD [ESP+8]\n");

X87_FMUL_REAL64PLUSOFFSET("ESP",8);

// fprintf(stdout," ADD ESP, 8 \n");

X86_ADD_REG32_VALUE32("ESP",8);

// fprintf(stdout," fstp QWORD [esp]\n" );

X87_FSTP_REAL64PLUSOFFSET("ESP",0);

}


void Div()
{
////////////////////////////////////////////////////
//fprintf(stdout, " pop ebx \n");
//

Pop("EBX");

//////////////////////////////////////////////////////
//
// fprintf(stdout," mov eax, [esp]\n");
//

X86_MOV_REG32_PTRREG32PLUSOFFSET("EAX","ESP",0);

///////////////////////////////////////////////
// fprintf(stdout," cdq\n" );
//
X86_CDQ();

//////////////////////////////////////////////////////
// fprintf(stdout," idiv ebx\n");
//

X86_IDIV_REG32("EBX");

////////////////////////////////////////////////////////
// fprintf(stdout," mov [esp], eax\n");
//
//
X86_MOV_PTRREG32_REG32("ESP","EAX");

}


void DivF()
{

////////////////////////////////////////////////
//fprintf(stdout," fld QWORD [esp+8] \n");
//

X87_FLD_REAL64PLUSOFFSET("ESP",8);

// fprintf(stdout," fdiv QWORD [ESP]\n");
X87_FDIV_REAL64PLUSOFFSET("ESP",0);

// fprintf(stdout,"ADD ESP, 8 \n");

X86_ADD_REG32_VALUE32("ESP",8);

// fprintf(stdout," fstp QWORD [esp]\n" );

X87_FSTP_REAL64PLUSOFFSET("ESP",0);

}

void Add()
{
///////////////////////////////////////////////////
// fprintf(stdout,"pop eax \n");
//
Pop("EAX");

///////////////////////////////////////////////
// fprintf(stdout,"add [esp], eax\n");
//
X86_ADD_PTRREG32PLUSOFFSET_REG32("ESP",0,"EAX");


}


void AddF()
{

/////////////////////////////////////////////
//fprintf(stdout," fld QWORD [esp] \n");

X87_FLD_REAL64PLUSOFFSET("ESP",0);

//fprintf(stdout," fadd QWORD [ESP+8]\n");
X87_FADD_REAL64PLUSOFFSET("ESP",8);

//fprintf(stdout," ADD ESP,8 \n");

X86_ADD_REG32_VALUE32("ESP",8);

/////////////////////////////////////////
//fprintf(stdout," fstp QWORD [esp]\n" );
X87_FSTP_REAL64PLUSOFFSET("ESP",0);
}

void Sub()
{
///////////////////////////////////////////////
// fprintf(stdout,"pop eax \n");
//
//

Pop("EAX");

////////////////////////////////////////
// fprintf(stdout,"neg eax\n" );
//

X86_NEG_REG32("EAX");


//////////////////////////////////////////////
// fprintf(stdout,"add [esp], eax\n");
//
X86_ADD_PTRREG32PLUSOFFSET_REG32("ESP",0,"EAX");


}

void SubF()
{
////////////////////////////////////////////
//fprintf(stdout," fld QWORD [esp+8] \n");

X87_FLD_REAL64PLUSOFFSET("ESP",8);

//fprintf(stdout," fsub QWORD [ESP]\n");

X87_FSUB_REAL64PLUSOFFSET("ESP",0);

//fprintf(stdout," ADD ESP,8 \n");
X86_ADD_REG32_VALUE32("ESP",8);

//fprintf(stdout," fstp QWORD [esp]\n" );

X87_FSTP_REAL64PLUSOFFSET("ESP",0);

}


void EmitPrologue( long num_items )
{
Push("EBP");
X86_MOV_EBP_ESP();
X86_SUB_REG32_VALUE32("ESP",num_items*8 );

}


void EmitEpilogue( long num_items )
{
X86_ADD_REG32_VALUE32("ESP",num_items*8 );
X86_MOV_ESP_EBP();
Pop("EBP");
X86_RET_EAX();
}

void PrintValue()
{
printf("MOV EAX, printbfr \n");
printf("push EAX\n");
printf("call _printf\n");
printf("ADD ESP,8\n");

}


void PrintValueF()
{


printf("MOV EAX, printbfrf \n");
printf("push EAX\n");
printf("call _printf\n");
printf("ADD ESP,12\n");

}

/////////////////////////////////////////////
//
//
//
//
static TOK_APP isKeyWord( char * Temp)
{
const char *mtemp = Temp;

static struct TABLE_KEYWORD
{
char *keywordname;
TOK_APP m_tok;
}KEYWORD_TABLE[] = {

{"DOUBLE",TOK_DT_DOUBLE},
{"SET",TOK_SET},
{"RETURN",TOK_RETURN},
{"Sin", TOK_SIN},
{"Cos",TOK_COS},
{"tan",TOK_TAN},
{"Abs",TOK_ABS},
{"PI",TOK_PI},
{"ASIN",TOK_ASIN},
{"ACOS",TOK_ACOS},
{"ATAN",TOK_ATAN},
{"EXP",TOK_EXP},
{"LN",TOK_LOG}


};


for( int i=0; i< sizeof(KEYWORD_TABLE) /
sizeof(KEYWORD_TABLE[0]); ++i )
{

if ( stricmp( KEYWORD_TABLE[i].keywordname ,mtemp )== 0 ){
return KEYWORD_TABLE[i].m_tok;
}

}


return TOK_NULL_VALUE;
}

///////////////////////////
//
//



struct CURR_VALUE curr_value;

char *inputstring;

char *input_ptr;
TOK_APP token_app;

SymbolTableManager SymbolTable;

TOK_APP ExtractLongorDouble();

TOK_APP next_token()
{

next_tok_label:

while ( *input_ptr == ' ' || *input_ptr == '\t' )
input_ptr++;

switch(*input_ptr)
{

case 13:
input_ptr +=2;
goto next_tok_label;
break;
case 10:
input_ptr +=1;
goto next_tok_label;
break;
case '*':
input_ptr++;
return TOK_MUL;
break;
case '/':
input_ptr++;
return TOK_DIV;
break;
case '-':
input_ptr++;
return TOK_SUB;
break;
case '+':
input_ptr++;
return TOK_ADD;
break;
case '(':
input_ptr++;
return TOK_OPAREN;
break;
case ')':
input_ptr++;
return TOK_CPAREN;
break;
case ';':
input_ptr++;
return TOK_SEMICOLON;
break;
case ',':
input_ptr++;
return TOK_COMMA;
break;
case '=':
input_ptr++;
return TOK_EQUAL;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':


if ( *input_ptr >= '0' && *input_ptr <='9' )
{

//curr_value.x = (double)(*input_ptr - '0');
//input_ptr++;
//return TOK_DOUBLE;

return ExtractLongorDouble();


}
break;
default:

if (*input_ptr == 0 )
return TOK_EOS;
if (!isalpha(*input_ptr) )
{
return TOK_ILLEGAL;
}

char *m_ptr = input_ptr;
char TempBuffer[100];
memset(TempBuffer,0,100);

char *unquoted_string = TempBuffer;
while ( isalnum(*input_ptr) || *input_ptr == '_' )
*unquoted_string++ = *input_ptr++;

strcpy(curr_value.String,TempBuffer);
TOK_APP ret_val;
if ( ( ret_val = isKeyWord( curr_value.String ) )
!= TOK_NULL_VALUE )
return ret_val;



return TOK_UNQUOTED_STRING;




}


}


void StatementSequence()
{

token_app = next_token();

while (token_app != TOK_EOS )
{

switch(token_app)
{
case TOK_DT_DOUBLE:
fprintf(stdout,"parsing decleration\n");
ParseDoubleDeclaration();
EmitPrologue( SymbolTable.GetSymbolCount());
break;
case TOK_SET:
fprintf(stdout,"parsing assignment\n");
ParseSetStatement();
break;
case TOK_RETURN:
fprintf(stdout,"parsing return \n");
ParseReturnStatement();
EmitEpilogue(SymbolTable.GetSymbolCount());
break;
default:
fprintf(stdout,"Token = %d\n", (long)token_app );
fprintf(stdout,"Error in Statement\n");
exit(0);
}

if (TOK_RETURN == token_app )
break;

token_app = next_token();


}

}

/////////////////////////////////////////
//
//
//
//
//
void ParseDoubleDeclaration()
{
char var_name[100];
SYMBOL_INFO loc_symb_info;
long nm;

next_var:
token_app = next_token();

if ( token_app != TOK_UNQUOTED_STRING )
{
fprintf(stdout,"Variable name expected\n");
exit(0);
}

strcpy( var_name , curr_value.String);

if ( SymbolTable.LookupSymbol(var_name) )
{
fprintf(stdout,"Duplicate Declaration\n"); exit(0);

}



strcpy(loc_symb_info.SymbolName,var_name);
loc_symb_info.smb_kind = variable;
loc_symb_info.smb_form = s_atomic;
loc_symb_info.smb_type = double_type ;
SymbolTable.AddSymbol( &loc_symb_info );

if ( (token_app = next_token() ) == TOK_COMMA )
{
goto next_var;

}


if (token_app != TOK_SEMICOLON )
{

fprintf(stdout,"Semi Colon expected\n");
exit(0);

}




}

void ParseSetStatement()
{

SYMBOL_INFO *m_ptr;


next_var:
token_app = next_token();
if ( token_app != TOK_UNQUOTED_STRING )
{
fprintf(stdout,"Variable name expected\n");
exit(0);
}

if ( (m_ptr = SymbolTable.LookupSymbol(curr_value.String)) == NULL)
{
fprintf(stdout,"Variable not found\n");
exit(0);

}



token_app = next_token();

if ( token_app != TOK_EQUAL )
{
fprintf(stdout,"Equal Expected\n");
exit(0);
}

expr_prime();
// token_app = next_token();
if ( token_app != TOK_SEMICOLON )
{
fprintf(stdout,"SemiColon Expected\n");
fprintf(stdout,"The Token parsed = %d\n", token_app);
exit(0);
} else {
X87_FLD_REAL64PLUSOFFSET("ESP",0);
X87_FSTP_REAL64PLUSOFFSET_EBP("EBP",- (4+ (m_ptr->ADDRESS.offset_from_EBP+1)*8) );
X86_POP_REG32("EAX");
X86_POP_REG32("EDX");




}

}

void ParseReturnStatement()
{
next_var:

expr_prime();
if ( token_app != TOK_SEMICOLON )
{
fprintf(stdout,"SemiColon Expected\n");
exit(0);
}

else
{
X87_FLD_REAL64PLUSOFFSET("ESP",0);
X86_POP_REG32("EAX");
X86_POP_REG32("EDX");

}


}

void ProcessSine()
{

token_app = next_token();
if (token_app != TOK_OPAREN )
{

fprintf(stdout,"( Expected\n");
exit(0);
}
expr_prime();
if ( token_app != TOK_CPAREN )
{
fprintf(stdout,") Expected\n");
exit(0);
}
else
{
X87_FLD_REAL64PLUSOFFSET("ESP",0);
X87_FSIN();
X87_FSTP_REAL64PLUSOFFSET("ESP",0);


}


}

void ProcessCoSine()
{
token_app = next_token();
if (token_app != TOK_OPAREN )
{

fprintf(stdout,"( Expected\n");
exit(0);
}
expr_prime();
if ( token_app != TOK_CPAREN )
{
fprintf(stdout,") Expected\n");
exit(0);
}
else
{
X87_FLD_REAL64PLUSOFFSET("ESP",0);
X87_FCOS();
X87_FSTP_REAL64PLUSOFFSET("ESP",0);


}


}

void ProcessTan()
{
token_app = next_token();
if (token_app != TOK_OPAREN )
{

fprintf(stdout,"( Expected\n");
exit(0);
}
expr_prime();
if ( token_app != TOK_CPAREN )
{
fprintf(stdout,") Expected\n");
exit(0);
}
else
{
X87_FLD_REAL64PLUSOFFSET("ESP",0);
X87_FSTP_REAL64PLUSOFFSET("ESP",0);


}

}


void DispatchFunction(TOK_APP token_app)
{

switch(token_app)
{
case TOK_SIN:
ProcessSine();
break;
case TOK_COS:
ProcessCoSine();
break;

}


}

void expr_prime()
{

token_app = next_token();
int loc_token;
term();

while ( token_app == TOK_ADD || token_app == TOK_SUB )
{
loc_token = token_app;

if (token_app == TOK_ADD)
printf(";+\n");
else
printf(";-\n");

token_app = next_token();


term();
if ( loc_token == TOK_ADD )
{
AddF();

}
else {

SubF();

}

}





}

void call_expression()
{

expr_prime();
if (token_app == TOK_EOS )
{

// PrintValueF();
// fprintf(stdout,"ret");
X87_FLD_REAL64PLUSOFFSET("ESP",0);
X86_POP_REG32("EAX");
X86_POP_REG32("EDX");
X86_RET_EAX();

}
else {
printf("Error in expression");

}



}


void term()
{
int loc_token;

factor();
while (token_app == TOK_MUL || token_app == TOK_DIV )
{
loc_token = token_app;
token_app = next_token();
factor();

if ( loc_token == TOK_MUL )
{
MulF();

}
else {

DivF();

}
}


}


void factor()
{
if ( token_app == TOK_DOUBLE )
{
Push( curr_value.x );

}
else if ( token_app == TOK_OPAREN )
{
expr_prime();

if ( token_app != TOK_CPAREN )
{
printf("Error in Token");
exit(0);

}


}
else if ( token_app == TOK_UNQUOTED_STRING )
{
SYMBOL_INFO *m_ptr;
m_ptr = SymbolTable.LookupSymbol(
curr_value.String) ;

if ( m_ptr == NULL )
{
fprintf(stdout,"Variable not found\n");
exit(0);
}

X86_SUB_REG32_VALUE32("ESP",8);
X87_FLD_REAL64PLUSOFFSET_EBP("EBP",-(4+ (m_ptr->ADDRESS.offset_from_EBP+1)*8));
X87_FSTP_REAL64PLUSOFFSET("ESP",0);


}
else if ((long) token_app > (long ) TOK_FUNC_START && (long) token_app < (long)TOK_FUNC_END)
{
DispatchFunction(token_app);

}
else {
printf("Error in Token");
exit(0);

}

token_app = next_token();


}



///////////////////////////////////////////////////
// method #5
// Extract numeric valu from the stream
// numericvalue can be long or double ( including
// exponential notation )
//
TOK_APP ExtractLongorDouble()
{
char Buffer[50];
char *m_ptr = Buffer;
int nctr = 0;
int is_dec = 0;
char m_ch;

while ( isdigit( ( m_ch = *input_ptr )) ||
toupper(m_ch) == 'E' ||
m_ch == '.' )
{

if ( m_ch == '.' )
{

if ( is_dec == 1 )
return TOK_ILLEGAL;

is_dec = 1;
*m_ptr++ = *input_ptr++;
continue;
}
else if ( toupper(m_ch) == 'E' )
{
*m_ptr =0;
int sign = 1;
double till_value = atof(Buffer);
double frac_value = 0.0;
m_ptr = Buffer;
input_ptr++;

if ( *input_ptr == '-' || *input_ptr == '+' )
{
if ( *input_ptr == '-' )
sign = -1;
input_ptr++;
}
if ( !isdigit(*input_ptr) )
return TOK_ILLEGAL;

while ( input_ptr && isdigit(*input_ptr) )
*m_ptr++ = *input_ptr++;


*m_ptr = 0;
frac_value = atof(Buffer);
if ( till_value == 0.0 )
{
if ( frac_value == 0.0 )
return TOK_ILLEGAL;

curr_value.x = ( sign == 1 ) ?
pow(10.0, (double)frac_value ) :
1.0/pow(10.0,(double)frac_value);
return TOK_DOUBLE;

}
else
{
curr_value.x = (sign==1) ? till_value*pow(10.0, frac_value ) :till_value/pow(10.0,frac_value);
return TOK_DOUBLE;

}


}


*m_ptr++ = *input_ptr++;



}

*m_ptr=0;
TOK_APP Curr_Token;
if ( is_dec == 0 )
{
curr_value.x = (double)atol( Buffer );
Curr_Token = TOK_DOUBLE;


}
else
{
curr_value.x = atof( Buffer );
Curr_Token = TOK_DOUBLE;


}


return Curr_Token;


}


/////////////////////////////////////
//
//
// User Entry Point ...
//
//
//
//
//

int main(int argc , char **argv)
{

unsigned long oldprotect;
CompiledCode rct;
int j;

printf("Praseed Pai's Dynamic Expression Evaluator \n");
printf(" http://praseedp.blogspot.com \n");

if (argc == 1 )
{
printf(";;Default arguement is 2*3+4\n");
inputstring = "return 2*3+4;";
}
else
{
inputstring = argv[1] ;

}

Code = (unsigned char *) malloc(2048);
ip=0;
memset(Code,0,2048);
input_ptr = inputstring;
StatementSequence();


VirtualProtect(Code, 2048 , PAGE_EXECUTE, &oldprotect);
rct = (double (*)())Code;
FlushInstructionCache(GetCurrentProcess(),0,0);
double rt = (*rct)();
VirtualProtect(Code, 2048, oldprotect, &oldprotect);

fprintf(stdout,"The Result of the function is %g\n",rt);

for( j=0; j< ip; ++j )
{

fprintf(stdout,"%x\t",Code[j]);

if (j%3 == 0 )
fprintf(stdout,"\n");
}
fprintf(stdout,"\n");

free(Code);
return 0;

}







Executing Machine Language Code from your Visual C++ Program

The following program executes machine language instructions (x86) stored in an
array.

//////////////////////////////////////////
//
// A Simple Program to demonstrate execution
// of x86 instruction from a buffer
//
// Written By Praseed Pai K.T
// http://praseedp.blogspot.com
//
//
//

long Add( long a , long b ) {

return a + b;
}


char addfunc[] = { 0x55, // push EBP
0x8B, 0xEC, // mov ebp,esp
0x8B, 0x45 , 0x08, // mov eax,dword ptr [ebp+8]
0x03, 0x45 , 0x0c, // add eax,dword ptr [ebp+12]
0x5D, // pop ebp
0xC3 // ret
};


#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

typedef long (*BIN_FUNC)( long a , long b );

int main( int argc , char **argv )
{

DWORD oldprotect ;

VirtualProtect(addfunc, 128 , PAGE_EXECUTE, &oldprotect);
BIN_FUNC func = (BIN_FUNC)((void *)addfunc);
FlushInstructionCache(GetCurrentProcess(),0,0);
long c = (*func)(4,3);
VirtualProtect(addfunc, 128, oldprotect, &oldprotect);
printf("%d\n",c );


}

Sunday, August 01, 2010

Clipper - What goes away will come back with a bang

In the early and mid 90s , Clipper Programming language was a popular tool for writing small business applications. Even to this day , Systems written in this language are empowering small and medium business to do their transactions.

I worked with Clipper between June 1993 and October 1996. I was good at mixing
Clipper , C ( Turbo C/C++ 1.0 ) and Tasm (Turbo Assembler ) to develop "fast" applications.

I switched to Windows 16 bit and 32 bit system programming from there and for all
practical purpose , Clipper vanished from my life. The Nostalgia for that language
was lingering in my mind all these days.

Couple of week back , in a K-MUG ( Kerala Microsoft User Group ) thread there was a discussion about changing the startup code to make entry point function with a different name ( other than main ). To demonstrate this , i installed DOSBOX and procured a Turbo C/C++ ver 3.0 compiler from a friend of mine. Unfortunately, the source directory was not copied into his archive and i could not achieve my objective.

While playing with DOSBOX , i tried re-compiling my Clipper Summer 87 release based Accounting / Inventory package which i wrote in the year 1994. The stuff worked fine and i could work with Binary under Windows 32 , Linux 32 bit and MAC OS X 64 bit using DOSBOX. ( With the help of DOSBOX , i could run my code on all the platforms )

I have experimented with Harbour project last year and had blogged about it . ( Read Clipper Nostalgia tag in my blog ) Harbour Compiler can compile a superset of Clipper 5.3 code. For that , i need to migrate my Clipper code from Summer 87 release to Clipper 5.3. By pinging my friends , finally i got Clipper 5.3 compiler.
After couple of hours of effort , i modified my code a bit to be correctly compiled
under Clipper 5.3

Then , i did download Harbour binaries for Visual C++ ( Ya, Harbour generates C code
from you Clipper code [ the C code generated by Harbour is an interesting read in
it's own right and that is a topic for another blog entry ] and you need to compile
the generated source using the Platform's native compiler. ). After setting some environment variables , i was ready for my port to Win32

To my surprise , the Code got translated into Visual C++ code correctly and with the harbour batch files (after a minor tweak ) , i generated a Win32 Executable !!!!!.
Some thing which was practically dead got resurrected. My joy knew no bounds.

I Played witht the executable to break it and it was rock solid. 12,000 lines of Clipper code got compiled and linked into Win32 executable without a single error.

I repeated the same stuff with GNU Linux ( Fedora 9 ) and MAC OS X ( Snow leopord )
using GCC and i am convinced that we can write Cross Platform applications with Clipper ( using Harbour Compiler and Visual C++ [ in Linux and MAC OS X , it is gcc ] )

I was solely focused on Microsoft Technologies all these years and ocassionally i used to foray into Unixes and Linux. In the past six months ( from February 14th to be exact ) i was experimenting with Cross Platform Programming.

I have now got solid expertize in Software portability and has helped couple of companies migrate their Windows applications to Linux and a Company to port Linux
Application to Windows.

Here are the stuff we can do to save our investment in existing software infrastructure

a ) if you have got a 16 bit application without source , but binary works fine ,
use DOSBOX to run the stuff under Win32,Win64 , Linux 32/64 , MAC OS X.

b) if you have got the source code of your Xbase application , use Harbour to generate native binaries for Windows , Linux and MAC OS X.

c) if you have got the source code of your Win32 Application and that is written
in C/C++ , use WineLib to port the stuff to MAC OS X and Linux

d) if your application is written using Visual Basic , use Wine to run under Linux
and MAC OS X ( it works in most cases )

e) if you have got a .NET application written for Windows , use Mono to run under
Windows, Linux and MAC OS X


if FOSS people are reading this , here is an opportunity to give Microsoft run for it's money. The above methods work for Xbase programs (80% of apps written between 1985 and 2000 MSDOS) , Visual C++/Visual Basic Programs (90% of apps written in the 32 bit world ) and .NET programs (2002 - Current ). It covers 90% of application code base under Windows. All can come to GNU Linux very fast. Then Microsoft will find it hard to come up with new technologies very fast . Any takers ?