diff options
| -rw-r--r-- | projects/Stacker/lib/compiler/Lexer.l | 234 | ||||
| -rw-r--r-- | projects/Stacker/lib/compiler/Makefile | 21 | ||||
| -rw-r--r-- | projects/Stacker/lib/compiler/README | 20 | ||||
| -rw-r--r-- | projects/Stacker/lib/compiler/StackerCompiler.cpp | 1728 | ||||
| -rw-r--r-- | projects/Stacker/lib/compiler/StackerCompiler.h | 224 | ||||
| -rw-r--r-- | projects/Stacker/lib/compiler/StackerParser.y | 190 | 
6 files changed, 2417 insertions, 0 deletions
| diff --git a/projects/Stacker/lib/compiler/Lexer.l b/projects/Stacker/lib/compiler/Lexer.l new file mode 100644 index 0000000..6087f88 --- /dev/null +++ b/projects/Stacker/lib/compiler/Lexer.l @@ -0,0 +1,234 @@ +/*===-- Lexer.l - Scanner for Stacker language -----------------*- C++ -*--===// +//  +//                     The LLVM Compiler Infrastructure +// +// This file was developed by Reid Spencer and donated to the LLVM research  +// group and is distributed under the University of Illinois Open Source  +// License. See LICENSE.TXT for details. +//  +//===----------------------------------------------------------------------===// +// +//  This file implements the flex scanner for Stacker languages files. +// +//===----------------------------------------------------------------------===*/ + +%option prefix="Stacker" +%option yylineno +%option nostdinit +%option never-interactive +%option batch +%option noyywrap +%option nodefault +%option 8bit +%option outfile="Lexer.cpp" +%option ecs +%option noreject +%option noyymore + +%{ + +#include "StackerCompiler.h" +#include "StackerParser.h" + +/* Conversion of text ints to binary */ +static uint64_t IntToVal(const char *Buffer) { +  uint64_t Result = 0; +  for (; *Buffer; Buffer++) { +    uint64_t OldRes = Result; +    Result *= 10; +    Result += *Buffer-'0'; +    if (Result < OldRes)   // Uh, oh, overflow detected!!! +      StackerCompiler::ThrowException("constant bigger than 64 bits detected!"); +  } +  return Result; +} + +/* Conversion of text hexadecimal ints to binary */ +static uint64_t HexIntToVal(const char *Buffer) { +  uint64_t Result = 0; +  for (; *Buffer; ++Buffer) { +    uint64_t OldRes = Result; +    Result *= 16; +    char C = *Buffer; +    if (C >= '0' && C <= '9') +      Result += C-'0'; +    else if (C >= 'A' && C <= 'F') +      Result += C-'A'+10; +    else if (C >= 'a' && C <= 'f') +      Result += C-'a'+10; + +    if (Result < OldRes)   // Uh, oh, overflow detected!!! +      StackerCompiler::ThrowException("constant bigger than 64 bits detected!"); +  } +  return Result; +} + +#define YY_NEVER_INTERACTIVE 1 +%} + +/* Comments start with a ; and go till end of line */ +Comment1	[#].*$ +/* You can also embed them in ( ... ) */ +Comment2	\(.*\) +/* We ignore white space */ +White		[ \t\n] + +/* jdentifiers start with a % sign */ +Identifier  	[A-Za-z][-A-Za-z0-9_]* + +/* Strings can contain any character except " and \ */ +String		\"[^\"]*\" + +/* Positive and negative integer constants*/ +PInteger	[+]?[0-9]+ +NInteger	-[0-9]+ +HexInteger 	0x[0-9A-Fa-f]+ + +/* Special Characters - name them to avoid flex confusion */ +Semi 		[;] +Colon 		[:] +Less		\< +More		\> +LessEq		\<\= +MoreEq		\>\= +NotEq		\<\> +Equal		\= +Plus		\+ +Minus		\- +Incr		\+\+ +Decr		\-\- +Mult		\* +Div		\/ +StarSlash	\*\/ +LShift		\<\< +RShift		\>\> +InStr		\<s +InNum		\<d +InChar		\<c +OutStr		\>s +OutNum		\>d +OutChar		\>c + +%% + +{Comment1}	{ /* Ignore comments */ } +{Comment2}	{ /* Ignore comments */ } + +{Colon}		{ return COLON; } +{Semi}		{ return SEMI; } + +TRUE		{ return TRUE; } +FALSE		{ return FALSE; } +ON		{ return TRUE; } +OFF		{ return FALSE; } +{Less}		{ return LESS; } +LT		{ return LESS; } +{More}		{ return MORE; } +GT		{ return MORE; } +{LessEq}	{ return LESS_EQUAL; } +LE		{ return LESS_EQUAL; } +{MoreEq}	{ return MORE_EQUAL; } +GE		{ return MORE_EQUAL; } +{NotEq}		{ return NOT_EQUAL; } +NE		{ return NOT_EQUAL; } +{Equal}		{ return EQUAL; } +EQ		{ return EQUAL; } + +{Plus}		{ return PLUS; } +{Minus}		{ return MINUS; } +{Incr}		{ return INCR; } +{Decr}		{ return DECR; } +{Mult}		{ return MULT; } +{Div}		{ return DIV; } +MOD		{ return MODULUS; } +NEG		{ return NEGATE; } +ABS		{ return ABS; } +MIN		{ return MIN; } +MAX		{ return MAX; } +{StarSlash}	{ return STAR_SLASH; } + +AND		{ return AND; } +OR		{ return OR; } +XOR		{ return XOR; } +{LShift}	{ return LSHIFT; } +{RShift}	{ return RSHIFT; } + +DROP		{ return DROP; } +NIP		{ return NIP; } +DUP		{ return DUP; } +SWAP		{ return SWAP; } +OVER		{ return OVER; } +PICK		{ return PICK; } +SELECT		{ return SELECT; } +ROT		{ return ROT; } +RROT		{ return RROT; } +ROLL		{ return ROLL; } +TUCK		{ return TUCK; } +DROP2		{ return DROP2; } +NIP2		{ return NIP2; } +DUP2		{ return DUP2; } +SWAP2		{ return SWAP2; } +OVER2		{ return OVER2; } +TUCK2		{ return TUCK2; } +ROT2		{ return ROT2; } +RROT2		{ return RROT2; } + +MALLOC		{ return MALLOC; } +FREE		{ return FREE; } +GET		{ return GET; } +PUT		{ return PUT; } + +IF		{ return IF; } +ELSE		{ return ELSE; } +ENDIF		{ return ENDIF; } +WHILE		{ return WHILE; } +END		{ return END; } + +RECURSE		{ return RECURSE; } +RETURN		{ return RETURN; } +EXIT		{ return EXIT; } +FORWARD		{ return FORWARD; } +TAB		{ return TAB; } +SPACE		{ return SPACE; } +CR		{ return CR; } + +{InStr}		{ return IN_STR; } +{InNum}		{ return IN_NUM; } +{InChar} 	{ return IN_CHAR; } + +{OutStr}	{ return OUT_STR; } +{OutNum}	{ return OUT_NUM; } +{OutChar} 	{ return OUT_CHAR; } + +MAIN		{ return MAIN; } + +DUMP		{ return DUMP; } + +!=		{ StackerCompiler::ThrowException( +		  "You probably meant to use a <> instead of !=" ); } + +==		{ StackerCompiler::ThrowException( +		  "You probably meant to use a single = .. this isn't C"); } + +{PInteger}      { Stackerlval.IntegerVal = IntToVal(yytext); return INTEGER; } +{NInteger}      { uint64_t Val = IntToVal(yytext+1); +		  // +1:  we have bigger negative range +		  if (Val > (uint64_t)INT64_MAX+1) +		    StackerCompiler::ThrowException( +		    "Constant too large for signed 64 bits!"); +                  Stackerlval.IntegerVal = -Val;  +		  return INTEGER;  +                } +{HexInteger} 	{ Stackerlval.IntegerVal = HexIntToVal(yytext+3);  +                   return INTEGER; +                } + +{String} 	{ yytext[strlen(yytext)-1] = 0;           // nuke end quote +		  Stackerlval.StringVal = strdup(yytext+1);  // Nuke start quote +		  return STRING; +                } + +{Identifier}    { Stackerlval.StringVal = strdup(yytext); return IDENTIFIER; } + +{White}         { /* Ignore whitespace */ } +%% diff --git a/projects/Stacker/lib/compiler/Makefile b/projects/Stacker/lib/compiler/Makefile new file mode 100644 index 0000000..4c89ca8 --- /dev/null +++ b/projects/Stacker/lib/compiler/Makefile @@ -0,0 +1,21 @@ +##===- projects/sample/lib/sample/Makefile -----------------*- Makefile -*-===## + +# +# Indicate where we are relative to the top of the source tree. +# +LEVEL=../../../.. + +# +# Give the name of a library.  This will build a dynamic version. +# +SHARED_LIBRARY=1 +LIBRARYNAME=stkr_compiler + +# +# Include Makefile.common so we know what to do. +# +include $(LEVEL)/Makefile.common + +ifdef PARSE_DEBUG +INCLUDES += -DPARSE_DEBUG +endif diff --git a/projects/Stacker/lib/compiler/README b/projects/Stacker/lib/compiler/README new file mode 100644 index 0000000..5f13cbb --- /dev/null +++ b/projects/Stacker/lib/compiler/README @@ -0,0 +1,20 @@ +This directory contains a sample language front end for LLVM. + +It is a *very* simple/crude implementation of FORTH. It has many +deficiencies but provides enough basics to give you an idea of  +what programming a new language front end for LLVM  looks like. + +To keep things simple, Stacker has the following limitations: +1. Only a single, global stack is manipulated. +2. There is no interpretation, everything is compiled. +3. There's no type/bounds checking .. you're on your own. +4. There's no floating point support. +5. Only stdin can be read. Only stdout can be written. No other  +   file I/O is supported. + +As such, this isn't a very useful language for anything other than +the most trivial of programs. It is, however, a good learning tool +(for both the author and the student). + +Reid Spencer +16 November 2003 diff --git a/projects/Stacker/lib/compiler/StackerCompiler.cpp b/projects/Stacker/lib/compiler/StackerCompiler.cpp new file mode 100644 index 0000000..6ebcae9 --- /dev/null +++ b/projects/Stacker/lib/compiler/StackerCompiler.cpp @@ -0,0 +1,1728 @@ +//===-- StackerCompiler.cpp - Parser for llvm assembly files ----*- C++ -*-===// +//  +//                     The LLVM Compiler Infrastructure +// +// This file was developed by Reid Spencer and donated to the LLVM research  +// group and is distributed under the University of Illinois Open Source  +// License. See LICENSE.TXT for details. +//  +//===----------------------------------------------------------------------===// +// +//  This file implements the compiler for the "Stacker" language. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//            Globasl - Global variables we use  +//===----------------------------------------------------------------------===// + +#include <llvm/Analysis/Verifier.h> +#include <llvm/iMemory.h> +#include <llvm/iOperators.h> +#include <llvm/iOther.h> +#include <llvm/iTerminators.h> +#include <Support/Statistic.h> +#include "StackerCompiler.h" +#include "StackerParser.h" +#include <string> + +// Lexer/Parser defined variables and functions +extern std::FILE *Stackerin; +extern int Stackerlineno; +extern char* Stackertext; +extern int Stackerleng; +extern int Stackerparse(); + +StackerCompiler* StackerCompiler::TheInstance = 0; + +static Statistic<> NumDefinitions( +	"numdefs","The # of definitions encoutered while compiling Stacker"); + +StackerCompiler::StackerCompiler() +    : CurFilename("") +    , TheModule(0) +    , TheFunction(0) +    , DefinitionType(0) +    , TheStack(0) +    , TheIndex(0) +    , TheScanf(0) +    , ThePrintf(0) +    , TheExit(0) +    , StrFormat(0) +    , NumFormat(0) +    , ChrFormat(0) +    , InStrFormat(0) +    , InNumFormat(0) +    , InChrFormat(0) +    , Zero(0) +    , One(0) +    , Two(0) +    , Three(0) +    , Four(0) +    , Five(0) +    , IZero(0) +    , IOne(0) +    , ITwo(0) +    , no_arguments() +    , echo(false) +    , stack_size(256) +    , stack_type(0) +{ +} + +StackerCompiler::~StackerCompiler() +{ +    // delete TheModule; << don't do this!  +    // TheModule is passed to caller of the compile() method .. its their  +    // problem.  Likewise for the other allocated objects (which become part  +    // of TheModule. +    TheModule = 0; +    DefinitionType = 0; +    TheStack = 0; +    TheIndex = 0; +} + +Module* +StackerCompiler::compile( +    const std::string& filename, +    bool should_echo, +    size_t the_stack_size +) +{ +    // TODO: Provide a global lock to protect the singled-threaded compiler +    // and its global variables. Should be in guard object on the stack so +    // that its destructor causes lock to be released (multiple exits from +    // this function). + +    // Assign parameters +    CurFilename = filename; +    echo = should_echo; +    stack_size = the_stack_size; + +    /// Default the file to read +    FILE *F = stdin; + +    /// +    if (filename != "-")  +    { +	F = fopen(filename.c_str(), "r"); + +	if (F == 0) +	{ +	    throw ParseException(filename,  +		"Could not open file '" + filename + "'"); +	} +    } + +    Module *Result; +    try  +    { +	// Create the module we'll return +	TheModule = new Module( CurFilename ); + +	// Create a type to represent the stack. This is the same as the LLVM  +	// Assembly type [ 256 x int ] +	stack_type = ArrayType::get( Type::IntTy, stack_size ); + +	// Create a global variable for the stack. Note the use of appending  +	// linkage linkage so that multiple modules will make the stack larger.  +	// Also note that the last argument causes the global to be inserted  +	// automatically into the module. +	TheStack = new GlobalVariable(  +	    /*type=*/ stack_type,  +	    /*isConstant=*/ false,  +	    /*Linkage=*/ GlobalValue::AppendingLinkage,  +	    /*initializer=*/0,  +	    /*name=*/ "_stack_", +	    /*parent=*/ TheModule  +	); + +	// Create a global variable for indexing into the stack. Note the use  +	// of LinkOnce linkage. Only one copy of _index_ will be retained  +	// after linking +	TheIndex = new GlobalVariable(  +	    /*type=*/Type::LongTy,  +	    /*isConstant=*/false, +	    /*Linkage=*/GlobalValue::LinkOnceLinkage,  +	    /*initializer=*/0,  +	    /*name=*/"_index_", +	    /*parent=*/TheModule +	); + +	// Create a function prototype for definitions. No parameters, no  +	// result.  This is used below any time a function is created. +	std::vector<const Type*> params; // No parameters +	DefinitionType = FunctionType::get( Type::VoidTy, params, false ); + +	// Create a function for printf(3) +	params.push_back( PointerType::get( Type::SByteTy ) ); +	FunctionType* printf_type =  +	    FunctionType::get( Type::IntTy, params, true ); +	ThePrintf = new Function(  +	    printf_type, GlobalValue::ExternalLinkage, "printf", TheModule); + +	// Create a function for scanf(3) +	TheScanf = new Function(  +	    printf_type, GlobalValue::ExternalLinkage, "scanf", TheModule); + +	// Create a function for exit(3) +	params.clear(); +	params.push_back( Type::IntTy ); +	FunctionType* exit_type =  +	    FunctionType::get( Type::VoidTy, params, false ); +	TheExit = new Function(  +	    exit_type, GlobalValue::ExternalLinkage, "exit", TheModule); + +	ConstantArray* str_format = ConstantArray::get("%s"); +	StrFormat = new GlobalVariable(  +	    /*type=*/ArrayType::get( Type::SByteTy,  3 ), +	    /*isConstant=*/true, +	    /*Linkage=*/GlobalValue::LinkOnceLinkage,  +	    /*initializer=*/str_format,  +	    /*name=*/"_str_format_", +	    /*parent=*/TheModule +	); + +	ConstantArray* in_str_format = ConstantArray::get(" %as"); +	InStrFormat = new GlobalVariable(  +	    /*type=*/ArrayType::get( Type::SByteTy,  5 ), +	    /*isConstant=*/true, +	    /*Linkage=*/GlobalValue::LinkOnceLinkage,  +	    /*initializer=*/in_str_format,  +	    /*name=*/"_in_str_format_", +	    /*parent=*/TheModule +	); + +	ConstantArray* num_format = ConstantArray::get("%d"); +	NumFormat = new GlobalVariable(  +	    /*type=*/ArrayType::get( Type::SByteTy,  3 ), +	    /*isConstant=*/true, +	    /*Linkage=*/GlobalValue::LinkOnceLinkage,  +	    /*initializer=*/num_format,  +	    /*name=*/"_num_format_", +	    /*parent=*/TheModule +	); + +	ConstantArray* in_num_format = ConstantArray::get(" %d"); +	InNumFormat = new GlobalVariable(  +	    /*type=*/ArrayType::get( Type::SByteTy,  4 ), +	    /*isConstant=*/true, +	    /*Linkage=*/GlobalValue::LinkOnceLinkage,  +	    /*initializer=*/in_num_format,  +	    /*name=*/"_in_num_format_", +	    /*parent=*/TheModule +	); + +	ConstantArray* chr_format = ConstantArray::get("%c"); +	ChrFormat = new GlobalVariable(  +	    /*type=*/ArrayType::get( Type::SByteTy,  3 ), +	    /*isConstant=*/true, +	    /*Linkage=*/GlobalValue::LinkOnceLinkage,  +	    /*initializer=*/chr_format,  +	    /*name=*/"_chr_format_", +	    /*parent=*/TheModule +	); + +	ConstantArray* in_chr_format = ConstantArray::get(" %c"); +	InChrFormat = new GlobalVariable(  +	    /*type=*/ArrayType::get( Type::SByteTy,  4 ), +	    /*isConstant=*/true, +	    /*Linkage=*/GlobalValue::LinkOnceLinkage,  +	    /*initializer=*/in_chr_format,  +	    /*name=*/"_in_chr_format_", +	    /*parent=*/TheModule +	); + +	// Get some constants so we aren't always creating them +	Zero = ConstantInt::get( Type::LongTy, 0 ); +	One = ConstantInt::get( Type::LongTy, 1 ); +	Two = ConstantInt::get( Type::LongTy, 2 ); +	Three = ConstantInt::get( Type::LongTy, 3 ); +	Four = ConstantInt::get( Type::LongTy, 4 ); +	Five = ConstantInt::get( Type::LongTy, 5 ); +	IZero = ConstantInt::get( Type::IntTy, 0 ); +	IOne = ConstantInt::get( Type::IntTy, 1 ); +	ITwo = ConstantInt::get( Type::IntTy, 2 ); + +	// Reset the current line number +	Stackerlineno = 1;     + +	// Reset the parser's input to F +	Stackerin = F;		// Set the input file. + +	// Let the parse know about this instance +	TheInstance = this; + +	// Parse the file. The parser (see StackParser.y) will call back to  +	// the StackCompiler via the "handle*" methods  +	Stackerparse();  + +	// Avoid potential illegal use (TheInstance might be on the stack) +	TheInstance = 0; + +    } catch (...) { +	if (F != stdin) fclose(F);      // Make sure to close file descriptor  +	throw;                          // if an exception is thrown +    } + +    // Close the file +    if (F != stdin) fclose(F); +     +    // Return the compiled module to the caller +    return TheModule; +} + +//===----------------------------------------------------------------------===// +//            Internal Functions, used by handleXXX below. +//            These represent the basic stack operations. +//===----------------------------------------------------------------------===// + +Instruction* +StackerCompiler::incr_stack_index( BasicBlock* bb, Value* ival = 0 ) +{ +    // Load the value from the TheIndex +    LoadInst* loadop = new LoadInst( TheIndex ); +    bb->getInstList().push_back( loadop ); + +    // Increment the loaded index value +    if ( ival == 0 ) ival = One; +    CastInst* caster = new CastInst( ival, Type::LongTy ); +    bb->getInstList().push_back( caster ); +    BinaryOperator* addop = BinaryOperator::create( Instruction::Add,  +	    loadop, caster); +    bb->getInstList().push_back( addop ); + +    // Store the incremented value +    StoreInst* storeop = new StoreInst( addop, TheIndex ); +    bb->getInstList().push_back( storeop ); +    return storeop; +} + +Instruction* +StackerCompiler::decr_stack_index( BasicBlock* bb, Value* ival = 0 ) +{ +    // Load the value from the TheIndex +    LoadInst* loadop = new LoadInst( TheIndex ); +    bb->getInstList().push_back( loadop ); + +    // Decrement the loaded index value +    if ( ival == 0 ) ival = One; +    CastInst* caster = new CastInst( ival, Type::LongTy ); +    bb->getInstList().push_back( caster ); +    BinaryOperator* subop = BinaryOperator::create( Instruction::Sub,  +	    loadop, caster); +    bb->getInstList().push_back( subop ); + +    // Store the incremented value +    StoreInst* storeop = new StoreInst( subop, TheIndex ); +    bb->getInstList().push_back( storeop ); + +    return storeop; +} + +Instruction* +StackerCompiler::get_stack_pointer( BasicBlock* bb, Value* index = 0 ) +{ +    // Load the value of the Stack Index  +    LoadInst* loadop = new LoadInst( TheIndex ); +    bb->getInstList().push_back( loadop ); + +    // Index into the stack to get its address. NOTE the use of two +    // elements in this vector. The first de-references the pointer that +    // "TheStack" represents. The second indexes into the pointed to array. +    // Think of the first index as getting the address of the 0th element +    // of the array. +    std::vector<Value*> indexVec; +    indexVec.push_back( Zero ); + +    if ( index == 0 ) +    { +	indexVec.push_back(loadop);	 +    } +    else +    { +	CastInst* caster = new CastInst( index, Type::LongTy ); +	bb->getInstList().push_back( caster ); +	BinaryOperator* subop = BinaryOperator::create(  +	    Instruction::Sub, loadop, caster ); +	bb->getInstList().push_back( subop ); +	indexVec.push_back(subop); +    } + +    // Get the address of the indexed stack element +    GetElementPtrInst* gep = new GetElementPtrInst( TheStack, indexVec ); +    bb->getInstList().push_back( gep );		// Put GEP in Block + +    return gep; +} + +Instruction* +StackerCompiler::push_value( BasicBlock* bb, Value* val ) +{ +    // Get location of  +    incr_stack_index(bb); + +    // Get the stack pointer +    GetElementPtrInst* gep = cast<GetElementPtrInst>(  +	    get_stack_pointer( bb ) ); + +    // Cast the value to an integer .. hopefully it works +    CastInst* cast_inst = new CastInst( val, Type::IntTy ); +    bb->getInstList().push_back( cast_inst ); + +    // Store the value +    StoreInst* storeop = new StoreInst( cast_inst, gep ); +    bb->getInstList().push_back( storeop ); + +    return storeop; +} + +Instruction* +StackerCompiler::push_integer(BasicBlock* bb, int32_t value ) +{ +    // Just push a constant integer value +    return push_value( bb, ConstantSInt::get( Type::IntTy, value ) ); +} + +Instruction* +StackerCompiler::pop_integer( BasicBlock*bb ) +{ +    // Get the stack pointer +    GetElementPtrInst* gep = cast<GetElementPtrInst>( +	get_stack_pointer( bb )); + +    // Load the value +    LoadInst* load_inst = new LoadInst( gep ); +    bb->getInstList().push_back( load_inst ); + +    // Decrement the stack index +    decr_stack_index( bb ); + +    // Return the value +    return load_inst; +} + +Instruction* +StackerCompiler::push_string( BasicBlock* bb, const char* value ) +{ +    // Get length of the string +    size_t len = strlen( value ); + +    // Create a type for the string constant. Length is +1 for  +    // the terminating 0. +    ArrayType* char_array = ArrayType::get( Type::SByteTy, len + 1 ); + +    // Create an initializer for the value +    ConstantArray* initVal = ConstantArray::get( value ); + +    // Create an internal linkage global variable to hold the constant. +    GlobalVariable* strconst = new GlobalVariable(  +	char_array,  +	/*isConstant=*/true,  +	GlobalValue::InternalLinkage,  +	/*initializer=*/initVal, +	"", +	TheModule +    ); + +    // Push the casted value +    return push_value( bb, strconst ); +} + +Instruction* +StackerCompiler::pop_string( BasicBlock* bb ) +{ +    // Get location of stack pointer +    GetElementPtrInst* gep = cast<GetElementPtrInst>( +	get_stack_pointer( bb )); + +    // Load the value from the stack +    LoadInst* loader = new LoadInst( gep ); +    bb->getInstList().push_back( loader ); + +    // Cast the integer to a sbyte* +    CastInst* caster = new CastInst( loader, PointerType::get(Type::SByteTy) ); +    bb->getInstList().push_back( caster ); + +    // Decrement stack index +    decr_stack_index( bb ); + +    // Return the value +    return caster; +} + +Instruction* +StackerCompiler::replace_top( BasicBlock* bb, Value* new_top, Value* index = 0 ) +{ +    // Get the stack pointer +    GetElementPtrInst* gep = cast<GetElementPtrInst>( +	    get_stack_pointer( bb, index )); +     +    // Store the value there +    StoreInst* store_inst = new StoreInst( new_top, gep ); +    bb->getInstList().push_back( store_inst ); + +    // Return the value +    return store_inst; +} + +Instruction* +StackerCompiler::stack_top( BasicBlock* bb, Value* index = 0 ) +{ +    // Get the stack pointer +    GetElementPtrInst* gep = cast<GetElementPtrInst>( +	get_stack_pointer( bb, index )); + +    // Load the value +    LoadInst* load_inst = new LoadInst( gep ); +    bb->getInstList().push_back( load_inst ); + +    // Return the value +    return load_inst; +} + +Instruction* +StackerCompiler::stack_top_string( BasicBlock* bb, Value* index = 0 ) +{ +    // Get location of stack pointer +    GetElementPtrInst* gep = cast<GetElementPtrInst>( +	get_stack_pointer( bb, index )); + +    // Load the value from the stack +    LoadInst* loader = new LoadInst( gep ); +    bb->getInstList().push_back( loader ); + +    // Cast the integer to a sbyte* +    CastInst* caster = new CastInst( loader, PointerType::get(Type::SByteTy) ); +    bb->getInstList().push_back( caster ); + +    // Return the value +    return caster; +} + +static void +add_block( Function*f, BasicBlock* bb ) +{ +    if ( ! f->empty() && f->back().getTerminator() == 0 ) +    { +	BranchInst* branch = new BranchInst(bb); +	f->back().getInstList().push_back( branch ); +    } +    f->getBasicBlockList().push_back( bb ); +} + + +//===----------------------------------------------------------------------===// +//            handleXXX - Handle semantics of parser productions +//===----------------------------------------------------------------------===// + +Module* +StackerCompiler::handle_module_start( ) +{ +    // Return the newly created module +    return TheModule; +} + +Module*  +StackerCompiler::handle_module_end( Module* mod ) +{ +    // Return the module. +    return mod; +} + +Module* +StackerCompiler::handle_definition_list_start() +{ +    return TheModule; +} + +Module*  +StackerCompiler::handle_definition_list_end( Module* mod, Function* definition ) +{ +    if ( ! definition->empty() ) +    { +	BasicBlock& last_block = definition->back(); +	if ( last_block.getTerminator() == 0 ) +	{ +	    last_block.getInstList().push_back( new ReturnInst() ); +	} +    } +    // Insert the definition into the module +    mod->getFunctionList().push_back( definition ); + +    // Bump our (sample) statistic. +    ++NumDefinitions; +    return mod; +} + +Function* +StackerCompiler::handle_main_definition( Function* func ) +{ +    // Set the name of the function defined as the Stacker main +    func->setName( "_MAIN_"); + +    // Create the actual main for the runtime system. +    //std::vector<const Type*> params; // No parameters +    //FunctionType* main_type = FunctionType::get( Type::IntTy, params, false ); +    Function* SystemMain = new Function( +	DefinitionType,  +	GlobalValue::ExternalLinkage, +	"main", TheModule); + +    // Create a basic block that just calls the STACKERMAIN function. Note +    // that the basic block is automatically inserted into the end of SystemMain +    BasicBlock* bb = new BasicBlock( (echo?"main":"a"), SystemMain ) ; +    bb->getInstList().push_back( new CallInst( func, no_arguments) ); +    bb->getInstList().push_back( new ReturnInst() );  + +    // Turn "_stack_" into an initialized variable since this is the main +    // module. This causes it to not be "external" but defined in this module. +    TheStack->setInitializer( Constant::getNullValue(stack_type) ); + +    // Turn "_index_" into an intialized variable for the same reason. +    TheIndex->setInitializer( Constant::getNullValue(Type::LongTy) ); +    return func; +} + +Function*  +StackerCompiler::handle_forward( char * name ) +{ +    // Just create a placeholder function +    Function* the_function = new Function (  +	DefinitionType,  +	GlobalValue::ExternalLinkage,  +	name );  +    assert( the_function->isExternal() ); + +    free( name ); +    return the_function; +} + +Function*  +StackerCompiler::handle_definition( char * name, Function* f ) +{ +    // Look up the function name in the module to see if it was forward +    // declared. +    Function* existing_function = TheModule->getNamedFunction( name ); + +#if 0 +    // If the function already exists... +    if ( existing_function ) +    { +	// Just get rid of the placeholder +	existing_function->dropAllReferences(); +	delete existing_function; +    } +#endif + +    // Just set the name of the function now that we know what it is. +    f->setName( name ); + +    free( name ); + +    return f; +} + +Function* +StackerCompiler::handle_word_list_start() +{ +    TheFunction = new Function(DefinitionType, GlobalValue::ExternalLinkage); +    return TheFunction; +} + +Function* +StackerCompiler::handle_word_list_end( Function* f, BasicBlock* bb ) +{ +    add_block( f, bb ); +    return f; +} + +BasicBlock*  +StackerCompiler::handle_if( char* ifTrue, char* ifFalse ) +{ +    // Create a basic block for the preamble +    BasicBlock* bb = new BasicBlock((echo?"if":"")); + +    // Get the condition value +    LoadInst* cond = cast<LoadInst>( pop_integer(bb) ); + +    // Compare the condition against 0  +    SetCondInst* cond_inst = new SetCondInst( Instruction::SetNE, cond,  +	ConstantSInt::get( Type::IntTy, 0) ); +    bb->getInstList().push_back( cond_inst ); + +    // Create an exit block +    BasicBlock* exit_bb = new BasicBlock((echo?"endif":"")); + +    // Create the true_block +    BasicBlock* true_bb = new BasicBlock((echo?"then":"")); + +    // Create the false_block +    BasicBlock* false_bb = 0; +    if ( ifFalse ) false_bb = new BasicBlock((echo?"else":"")); + +    // Create a branch on the SetCond +    BranchInst* br_inst = new BranchInst( true_bb,  +	( ifFalse ? false_bb : exit_bb ), cond_inst ); +    bb->getInstList().push_back( br_inst ); + +    // Fill the true block  +    std::vector<Value*> args; +    if ( Function* true_func = TheModule->getNamedFunction(ifTrue) ) +    { +	true_bb->getInstList().push_back(  +		new CallInst( true_func, args ) ); +	true_bb->getInstList().push_back(  +		new BranchInst( exit_bb ) ); +    } +    else +    { +	ThrowException(std::string("Function '") + ifTrue +  +	    "' must be declared first.'"); +    } + +    free( ifTrue ); + +    // Fill the false block +    if ( false_bb ) +    { +	if ( Function* false_func = TheModule->getNamedFunction(ifFalse) ) +	{ +	    false_bb->getInstList().push_back(  +		    new CallInst( false_func, args ) ); +	    false_bb->getInstList().push_back(  +		    new BranchInst( exit_bb ) ); +	} +	else +	{ +	    ThrowException(std::string("Function '") + ifFalse +  +		    "' must be declared first.'"); +	} +	free( ifFalse ); +    } + +    // Add the blocks to the function +    add_block( TheFunction, bb ); +    add_block( TheFunction, true_bb ); +    if ( false_bb ) add_block( TheFunction, false_bb ); + +    return exit_bb; +} + +BasicBlock*  +StackerCompiler::handle_while( char* todo ) +{ + +    // Create a basic block for the loop test +    BasicBlock* test = new BasicBlock((echo?"while":"")); + +    // Create an exit block +    BasicBlock* exit = new BasicBlock((echo?"end":"")); + +    // Create a loop body block +    BasicBlock* body = new BasicBlock((echo?"do":"")); + +    // Create a root node +    BasicBlock* bb = new BasicBlock((echo?"root":"")); +    BranchInst* root_br_inst = new BranchInst( test ); +    bb->getInstList().push_back( root_br_inst ); + +    // Pop the condition value +    LoadInst* cond = cast<LoadInst>( stack_top(test) ); + +    // Compare the condition against 0  +    SetCondInst* cond_inst = new SetCondInst(  +	Instruction::SetNE, cond, ConstantSInt::get( Type::IntTy, 0) ); +    test->getInstList().push_back( cond_inst ); + +    // Add the branch instruction +    BranchInst* br_inst = new BranchInst( body, exit, cond_inst ); +    test->getInstList().push_back( br_inst ); + +    // Fill in the body +    std::vector<Value*> args; +    if ( Function* body_func = TheModule->getNamedFunction(todo) ) +    { +	body->getInstList().push_back( new CallInst( body_func, args ) ); +	body->getInstList().push_back( new BranchInst( test ) ); +    } +    else +    { +	ThrowException(std::string("Function '") + todo +  +	    "' must be declared first.'"); +    } + +    free( todo ); + +    // Add the blocks +    add_block( TheFunction, bb ); +    add_block( TheFunction, test ); +    add_block( TheFunction, body ); + +    return exit; +} + +BasicBlock*  +StackerCompiler::handle_identifier( char * name ) +{ +    Function* func = TheModule->getNamedFunction( name ); +    BasicBlock* bb = new BasicBlock((echo?"call":"")); +    if ( func ) +    { +	CallInst* call_def = new CallInst( func , no_arguments ); +	bb->getInstList().push_back( call_def ); +    } +    else +    { +	ThrowException(std::string("Definition '") + name +  +	    "' must be defined before it can be used."); +    } + +    free( name ); +    return bb; +} + +BasicBlock*  +StackerCompiler::handle_string( char * value ) +{ +    // Create a new basic block for the push operation +    BasicBlock* bb = new BasicBlock((echo?"string":"")); + +    // Push the string onto the stack +    push_string(bb, value); + +    // Free the strdup'd string +    free( value ); + +    return bb; +} + +BasicBlock*  +StackerCompiler::handle_integer( const int32_t value ) +{ +    // Create a new basic block for the push operation +    BasicBlock* bb = new BasicBlock((echo?"int":"")); + +    // Push the integer onto the stack +    push_integer(bb, value ); + +    return bb; +} + +BasicBlock*  +StackerCompiler::handle_word( int tkn ) +{ +    // Create a new basic block to hold the instruction(s) +    BasicBlock* bb = new BasicBlock(); + +    /* Fill the basic block with the appropriate instructions */ +    switch ( tkn ) +    { +    case DUMP :  // Dump the stack (debugging aid) +    { +	if (echo) bb->setName("DUMP"); +	Function* f = TheModule->getOrInsertFunction( +	    "_stacker_dump_stack_", DefinitionType); +	std::vector<Value*> args; +	bb->getInstList().push_back( new CallInst( f, args ) ); +	break; +    } + +    // Logical Operations +    case TRUE :  // -- -1 +    { +	if (echo) bb->setName("TRUE"); +	push_integer(bb,-1);  +	break; +    } +    case FALSE : // -- 0 +    { +	if (echo) bb->setName("FALSE"); +	push_integer(bb,0);  +	break; +    } +    case LESS : // w1 w2 -- w2<w1 +    { +	if (echo) bb->setName("LESS"); +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	LoadInst* op2 = cast<LoadInst>(pop_integer(bb)); +	SetCondInst* cond_inst =  +	    new SetCondInst( Instruction::SetLT, op1, op2 ); +	bb->getInstList().push_back( cond_inst ); +	push_value( bb, cond_inst ); +	break; +    } +    case MORE : // w1 w2 -- w2>w1 +    { +	if (echo) bb->setName("MORE"); +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	LoadInst* op2 = cast<LoadInst>(pop_integer(bb)); +	SetCondInst* cond_inst =  +	    new SetCondInst( Instruction::SetGT, op1, op2 ); +	bb->getInstList().push_back( cond_inst ); +	push_value( bb, cond_inst ); +	break; +    } +    case LESS_EQUAL : // w1 w2 -- w2<=w1 +    { +	if (echo) bb->setName("LE"); +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	LoadInst* op2 = cast<LoadInst>(pop_integer(bb)); +	SetCondInst* cond_inst =  +	    new SetCondInst( Instruction::SetLE, op1, op2 ); +	bb->getInstList().push_back( cond_inst ); +	push_value( bb, cond_inst ); +	break; +    } +    case MORE_EQUAL : // w1 w2 -- w2>=w1 +    { +	if (echo) bb->setName("GE"); +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	LoadInst* op2 = cast<LoadInst>(pop_integer(bb)); +	SetCondInst* cond_inst =  +	    new SetCondInst( Instruction::SetGE, op1, op2 ); +	bb->getInstList().push_back( cond_inst ); +	push_value( bb, cond_inst ); +	break; +    } +    case NOT_EQUAL : // w1 w2 -- w2!=w1 +    { +	if (echo) bb->setName("NE"); +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	LoadInst* op2 = cast<LoadInst>(pop_integer(bb)); +	SetCondInst* cond_inst =  +	    new SetCondInst( Instruction::SetNE, op1, op2 ); +	bb->getInstList().push_back( cond_inst ); +	push_value( bb, cond_inst ); +	break; +    } +    case EQUAL : // w1 w2 -- w1==w2 +    { +	if (echo) bb->setName("EQ"); +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	LoadInst* op2 = cast<LoadInst>(pop_integer(bb)); +	SetCondInst* cond_inst =  +	    new SetCondInst( Instruction::SetEQ, op1, op2 ); +	bb->getInstList().push_back( cond_inst ); +	push_value( bb, cond_inst ); +	break; +    } + +    // Arithmetic Operations +    case PLUS : // w1 w2 -- w2+w1 +    { +	if (echo) bb->setName("ADD"); +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	LoadInst* op2 = cast<LoadInst>(pop_integer(bb)); +	BinaryOperator* addop =  +	    BinaryOperator::create( Instruction::Add, op1, op2); +	bb->getInstList().push_back( addop ); +	push_value( bb, addop ); +	break; +    } +    case MINUS : // w1 w2 -- w2-w1 +    { +	if (echo) bb->setName("SUB"); +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	LoadInst* op2 = cast<LoadInst>(pop_integer(bb)); +	BinaryOperator* subop =  +	    BinaryOperator::create( Instruction::Sub, op1, op2); +	bb->getInstList().push_back( subop ); +	push_value( bb, subop ); +	break; +    } +    case INCR :  // w1 -- w1+1 +    { +	if (echo) bb->setName("INCR"); +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	BinaryOperator* addop =  +	    BinaryOperator::create( Instruction::Add, op1, IOne ); +	bb->getInstList().push_back( addop ); +	push_value( bb, addop ); +	break; +    } +    case DECR : // w1 -- w1-1 +    { +	if (echo) bb->setName("DECR"); +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	BinaryOperator* subop = BinaryOperator::create( Instruction::Sub, op1, +	    ConstantSInt::get( Type::IntTy, 1 ) ); +	bb->getInstList().push_back( subop ); +	push_value( bb, subop ); +	break; +    } +    case MULT : // w1 w2 -- w2*w1 +    { +	if (echo) bb->setName("MUL"); +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	LoadInst* op2 = cast<LoadInst>(pop_integer(bb)); +	BinaryOperator* multop =  +	    BinaryOperator::create( Instruction::Mul, op1, op2); +	bb->getInstList().push_back( multop ); +	push_value( bb, multop ); +	break; +    } +    case DIV :// w1 w2 -- w2/w1 +    { +	if (echo) bb->setName("DIV"); +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	LoadInst* op2 = cast<LoadInst>(pop_integer(bb)); +	BinaryOperator* divop =  +	    BinaryOperator::create( Instruction::Div, op1, op2); +	bb->getInstList().push_back( divop ); +	push_value( bb, divop ); +	break; +    } +    case MODULUS : // w1 w2 -- w2%w1 +    { +	if (echo) bb->setName("MOD"); +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	LoadInst* op2 = cast<LoadInst>(pop_integer(bb)); +	BinaryOperator* divop =  +	    BinaryOperator::create( Instruction::Rem, op1, op2); +	bb->getInstList().push_back( divop ); +	push_value( bb, divop ); +	break; +    } +    case STAR_SLASH : // w1 w2 w3 -- (w3*w2)/w1 +    { +	if (echo) bb->setName("STAR_SLASH"); +	// Get the operands +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	LoadInst* op2 = cast<LoadInst>(pop_integer(bb)); +	LoadInst* op3 = cast<LoadInst>(pop_integer(bb)); + +	// Multiply the first two +	BinaryOperator* multop =  +	    BinaryOperator::create( Instruction::Mul, op1, op2); +	bb->getInstList().push_back( multop ); + +	// Divide by the third operand +	BinaryOperator* divop =  +	    BinaryOperator::create( Instruction::Div, multop, op3); +	bb->getInstList().push_back( divop ); + +	// Push the result +	push_value( bb, divop ); + +	break; +    } +    case NEGATE : // w1 -- -w1 +    { +	if (echo) bb->setName("NEG"); +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	// APPARENTLY, the following doesn't work: +	// BinaryOperator* negop = BinaryOperator::createNeg( op1 ); +	// bb->getInstList().push_back( negop ); +	// So we'll multiply by -1 (ugh) +	BinaryOperator* multop = BinaryOperator::create( Instruction::Mul, op1, +	    ConstantSInt::get( Type::IntTy, -1 ) ); +	bb->getInstList().push_back( multop ); +	push_value( bb, multop ); +	break; +    } +    case ABS : // w1 -- |w1| +    { +	if (echo) bb->setName("ABS"); +	// Get the top of stack value +	LoadInst* op1 = cast<LoadInst>(stack_top(bb)); + +	// Determine if its negative +	SetCondInst* cond_inst =  +	    new SetCondInst( Instruction::SetLT, op1, IZero ); +	bb->getInstList().push_back( cond_inst ); + +	// Create a block for storing the result +	BasicBlock* exit_bb = new BasicBlock((echo?"exit":"")); + +	// Create a block for making it a positive value +	BasicBlock* pos_bb = new BasicBlock((echo?"neg":"")); + +	// Create the branch on the SetCond +	BranchInst* br_inst = new BranchInst( pos_bb, exit_bb, cond_inst ); +	bb->getInstList().push_back( br_inst ); + +	// Fill out the negation block +	LoadInst* pop_op = cast<LoadInst>( pop_integer(pos_bb) ); +	BinaryOperator* neg_op = BinaryOperator::createNeg( pop_op ); +	pos_bb->getInstList().push_back( neg_op ); +	push_value( pos_bb, neg_op ); +	pos_bb->getInstList().push_back( new BranchInst( exit_bb ) ); + +	// Add the new blocks in the correct order +	add_block( TheFunction, bb ); +	add_block( TheFunction, pos_bb ); +	bb = exit_bb; +	break; +    } +    case MIN : // w1 w2 -- (w2<w1?w2:w1) +    { +	if (echo) bb->setName("MIN"); + +	// Create the three blocks +	BasicBlock* exit_bb  = new BasicBlock((echo?"exit":"")); +	BasicBlock* op1_block = new BasicBlock((echo?"less":"")); +	BasicBlock* op2_block = new BasicBlock((echo?"more":"")); + +	// Get the two operands +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	LoadInst* op2 = cast<LoadInst>(pop_integer(bb)); + +	// Compare them  +	SetCondInst* cond_inst =  +	    new SetCondInst( Instruction::SetLT, op1, op2); +	bb->getInstList().push_back( cond_inst ); + +	// Create a branch on the SetCond +	BranchInst* br_inst =  +	    new BranchInst( op1_block, op2_block, cond_inst ); +	bb->getInstList().push_back( br_inst ); + +	// Create a block for pushing the first one +	push_value(op1_block, op1); +	op1_block->getInstList().push_back( new BranchInst( exit_bb ) ); + +	// Create a block for pushing the second one +	push_value(op2_block, op2); +	op2_block->getInstList().push_back( new BranchInst( exit_bb ) ); + +	// Add the blocks +	add_block( TheFunction, bb ); +	add_block( TheFunction, op1_block ); +	add_block( TheFunction, op2_block ); +	bb = exit_bb; +	break; +    } +    case MAX : // w1 w2 -- (w2>w1?w2:w1) +    { +	if (echo) bb->setName("MAX"); +	// Get the two operands +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	LoadInst* op2 = cast<LoadInst>(pop_integer(bb)); + +	// Compare them  +	SetCondInst* cond_inst =  +	    new SetCondInst( Instruction::SetGT, op1, op2); +	bb->getInstList().push_back( cond_inst ); + +	// Create an exit block +	BasicBlock* exit_bb = new BasicBlock((echo?"exit":"")); + +	// Create a block for pushing the larger one +	BasicBlock* op1_block = new BasicBlock((echo?"more":"")); +	push_value(op1_block, op1); +	op1_block->getInstList().push_back( new BranchInst( exit_bb ) ); + +	// Create a block for pushing the smaller or equal one +	BasicBlock* op2_block = new BasicBlock((echo?"less":"")); +	push_value(op2_block, op2); +	op2_block->getInstList().push_back( new BranchInst( exit_bb ) ); + +	// Create a banch on the SetCond +	BranchInst* br_inst =  +	    new BranchInst( op1_block, op2_block, cond_inst ); +	bb->getInstList().push_back( br_inst ); + +	// Add the blocks +	add_block( TheFunction, bb ); +	add_block( TheFunction, op1_block ); +	add_block( TheFunction, op2_block ); + +	bb = exit_bb; +	break; +    } + +    // Bitwise Operators +    case AND : // w1 w2 -- w2&w1 +    { +	if (echo) bb->setName("AND"); +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	LoadInst* op2 = cast<LoadInst>(pop_integer(bb)); +	BinaryOperator* andop =  +	    BinaryOperator::create( Instruction::And, op1, op2); +	bb->getInstList().push_back( andop ); +	push_value( bb, andop ); +	break; +    } +    case OR : // w1 w2 -- w2|w1 +    { +	if (echo) bb->setName("OR"); +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	LoadInst* op2 = cast<LoadInst>(pop_integer(bb)); +	BinaryOperator* orop =  +	    BinaryOperator::create( Instruction::Or, op1, op2); +	bb->getInstList().push_back( orop ); +	push_value( bb, orop ); +	break; +    } +    case XOR : // w1 w2 -- w2^w1 +    { +	if (echo) bb->setName("XOR"); +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	LoadInst* op2 = cast<LoadInst>(pop_integer(bb)); +	BinaryOperator* xorop =  +	    BinaryOperator::create( Instruction::Xor, op1, op2); +	bb->getInstList().push_back( xorop ); +	push_value( bb, xorop ); +	break; +    } +    case LSHIFT : // w1 w2 -- w1<<w2 +    { +	if (echo) bb->setName("SHL"); +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	LoadInst* op2 = cast<LoadInst>(pop_integer(bb)); +	CastInst* castop = new CastInst( op1, Type::UByteTy ); +	bb->getInstList().push_back( castop ); +	ShiftInst* shlop = new ShiftInst( Instruction::Shl, op2, castop ); +	bb->getInstList().push_back( shlop ); +	push_value( bb, shlop ); +	break; +    } +    case RSHIFT :  // w1 w2 -- w1>>w2 +    { +	if (echo) bb->setName("SHR"); +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); +	LoadInst* op2 = cast<LoadInst>(pop_integer(bb)); +	CastInst* castop = new CastInst( op1, Type::UByteTy ); +	bb->getInstList().push_back( castop ); +	ShiftInst* shrop = new ShiftInst( Instruction::Shr, op2, castop ); +	bb->getInstList().push_back( shrop ); +	push_value( bb, shrop ); +	break; +    } + +    // Stack Manipulation Operations +    case DROP:   	// w --  +    { +	if (echo) bb->setName("DROP"); +	decr_stack_index(bb, One); +	break; +    } +    case DROP2:	// w1 w2 --  +    { +	if (echo) bb->setName("DROP2"); +	decr_stack_index( bb, Two ); +	break; +    } +    case NIP:	// w1 w2 -- w2 +    { +	if (echo) bb->setName("NIP"); +	LoadInst* w2 = cast<LoadInst>( stack_top( bb ) ); +	decr_stack_index( bb  ); +	replace_top( bb, w2 ); +	break; +    } +    case NIP2:	// w1 w2 w3 w4 -- w3 w4 +    { +	if (echo) bb->setName("NIP2"); +	LoadInst* w4 = cast<LoadInst>( stack_top( bb ) ); +	LoadInst* w3 = cast<LoadInst>( stack_top( bb, One ) ); +	decr_stack_index( bb, Two ); +	replace_top( bb, w4 ); +	replace_top( bb, w3, One ); +	break; +    } +    case DUP:	// w -- w w +    { +	if (echo) bb->setName("DUP"); +	LoadInst* w = cast<LoadInst>( stack_top( bb ) ); +	push_value( bb, w ); +	break; +    } +    case DUP2:	// w1 w2 -- w1 w2 w1 w2 +    { +	if (echo) bb->setName("DUP2"); +	LoadInst* w2 = cast<LoadInst>( stack_top(bb) ); +	LoadInst* w1 = cast<LoadInst>( stack_top(bb, One ) ); +	incr_stack_index( bb, Two ); +	replace_top( bb, w1, One ); +	replace_top( bb, w2 ); +	break; +    } +    case SWAP:	// w1 w2 -- w2 w1 +    { +	if (echo) bb->setName("SWAP"); +	LoadInst* w2 = cast<LoadInst>( stack_top( bb ) ); +	LoadInst* w1 = cast<LoadInst>( stack_top( bb, One ) ); +	replace_top( bb, w1 ); +	replace_top( bb, w2, One ); +	break; +    } +    case SWAP2:	// w1 w2 w3 w4 -- w3 w4 w1 w2 +    { +	if (echo) bb->setName("SWAP2"); +	LoadInst* w4 = cast<LoadInst>( stack_top( bb ) ); +	LoadInst* w3 = cast<LoadInst>( stack_top( bb, One ) ); +	LoadInst* w2 = cast<LoadInst>( stack_top( bb, Two ) ); +	LoadInst* w1 = cast<LoadInst>( stack_top( bb, Three ) ); +	replace_top( bb, w2 ); +	replace_top( bb, w1, One ); +	replace_top( bb, w4, Two ); +	replace_top( bb, w3, Three ); +	break; +    } +    case OVER:	// w1 w2 -- w1 w2 w1 +    { +	if (echo) bb->setName("OVER"); +	LoadInst* w1 = cast<LoadInst>( stack_top( bb, One ) ); +	push_value( bb, w1 ); +	break; +    } +    case OVER2:	// w1 w2 w3 w4 -- w1 w2 w3 w4 w1 w2 +    { +	if (echo) bb->setName("OVER2"); +	LoadInst* w2 = cast<LoadInst>( stack_top( bb, Two ) ); +	LoadInst* w1 = cast<LoadInst>( stack_top( bb, Three ) ); +	incr_stack_index( bb, Two ); +	replace_top( bb, w2 ); +	replace_top( bb, w1, One ); +	break; +    } +    case ROT:	// w1 w2 w3 -- w2 w3 w1 +    { +	if (echo) bb->setName("ROT"); +	LoadInst* w3 = cast<LoadInst>( stack_top( bb ) ); +	LoadInst* w2 = cast<LoadInst>( stack_top( bb, One ) ); +	LoadInst* w1 = cast<LoadInst>( stack_top( bb, Two ) ); +	replace_top( bb, w1 ); +	replace_top( bb, w3, One ); +	replace_top( bb, w2, Two ); +	break; +    } +    case ROT2:	// w1 w2 w3 w4 w5 w6 -- w3 w4 w5 w6 w1 w2 +    { +	if (echo) bb->setName("ROT2"); +	LoadInst* w6 = cast<LoadInst>( stack_top( bb ) ); +	LoadInst* w5 = cast<LoadInst>( stack_top( bb, One ) ); +	LoadInst* w4 = cast<LoadInst>( stack_top( bb, Two ) ); +	LoadInst* w3 = cast<LoadInst>( stack_top( bb, Three) ); +	LoadInst* w2 = cast<LoadInst>( stack_top( bb, Four ) ); +	LoadInst* w1 = cast<LoadInst>( stack_top( bb, Five ) ); +	replace_top( bb, w2 ); +	replace_top( bb, w1, One ); +	replace_top( bb, w6, Two ); +	replace_top( bb, w5, Three ); +	replace_top( bb, w4, Four ); +	replace_top( bb, w3, Five ); +	break; +    } +    case RROT:	// w1 w2 w3 -- w3 w1 w2 +    { +	if (echo) bb->setName("RROT2"); +	LoadInst* w3 = cast<LoadInst>( stack_top( bb ) ); +	LoadInst* w2 = cast<LoadInst>( stack_top( bb, One ) ); +	LoadInst* w1 = cast<LoadInst>( stack_top( bb, Two ) ); +	replace_top( bb, w2 ); +	replace_top( bb, w1, One ); +	replace_top( bb, w3, Two ); +	break; +    } +    case RROT2:	// w1 w2 w3 w4 w5 w6 -- w5 w6 w1 w2 w3 w4 +    { +	if (echo) bb->setName("RROT2"); +	LoadInst* w6 = cast<LoadInst>( stack_top( bb ) ); +	LoadInst* w5 = cast<LoadInst>( stack_top( bb, One ) ); +	LoadInst* w4 = cast<LoadInst>( stack_top( bb, Two ) ); +	LoadInst* w3 = cast<LoadInst>( stack_top( bb, Three) ); +	LoadInst* w2 = cast<LoadInst>( stack_top( bb, Four ) ); +	LoadInst* w1 = cast<LoadInst>( stack_top( bb, Five ) ); +	replace_top( bb, w4 ); +	replace_top( bb, w3, One ); +	replace_top( bb, w2, Two ); +	replace_top( bb, w1, Three ); +	replace_top( bb, w6, Four ); +	replace_top( bb, w5, Five ); +	break; +    } +    case TUCK:	// w1 w2 -- w2 w1 w2 +    { +	if (echo) bb->setName("TUCK"); +	LoadInst* w2 = cast<LoadInst>( stack_top( bb ) ); +	LoadInst* w1 = cast<LoadInst>( stack_top( bb, One ) ); +	incr_stack_index( bb ); +	replace_top( bb, w2 ); +	replace_top( bb, w1, One ); +	replace_top( bb, w2, Two ); +	break; +    } +    case TUCK2:	// w1 w2 w3 w4 -- w3 w4 w1 w2 w3 w4  +    { +	if (echo) bb->setName("TUCK2"); +	LoadInst* w4 = cast<LoadInst>( stack_top( bb ) ); +	LoadInst* w3 = cast<LoadInst>( stack_top( bb, One ) ); +	LoadInst* w2 = cast<LoadInst>( stack_top( bb, Two ) ); +	LoadInst* w1 = cast<LoadInst>( stack_top( bb, Three) ); +	incr_stack_index( bb, Two ); +	replace_top( bb, w4 ); +	replace_top( bb, w3, One ); +	replace_top( bb, w2, Two ); +	replace_top( bb, w1, Three ); +	replace_top( bb, w4, Four ); +	replace_top( bb, w3, Five ); +	break; +    } +    case ROLL:	// x0 x1 .. xn n -- x1 .. xn x0 +    { +	/// THIS OEPRATOR IS OMITTED PURPOSEFULLY AND IS LEFT TO THE  +	/// READER AS AN EXERCISE. THIS IS ONE OF THE MORE COMPLICATED +	/// OPERATORS. IF YOU CAN GET THIS ONE RIGHT, YOU COMPLETELY +	/// UNDERSTAND HOW BOTH LLVM AND STACKER WOR.   +	/// HINT: LOOK AT PICK AND SELECT. ROLL IS SIMILAR. +	if (echo) bb->setName("ROLL"); +	break; +    } +    case PICK:	// x0 ... Xn n -- x0 ... Xn x0 +    { +	if (echo) bb->setName("PICK"); +	LoadInst* n = cast<LoadInst>( stack_top( bb ) ); +	BinaryOperator* addop =  +	    BinaryOperator::create( Instruction::Add, n, IOne ); +	bb->getInstList().push_back( addop ); +	LoadInst* x0 = cast<LoadInst>( stack_top( bb, addop ) ); +	replace_top( bb, x0 ); +	break; +    } +    case SELECT:	// m n X0..Xm Xm+1 .. Xn -- Xm +    { +	if (echo) bb->setName("SELECT"); +	LoadInst* m = cast<LoadInst>( stack_top(bb) ); +	LoadInst* n = cast<LoadInst>( stack_top(bb, One) ); +	BinaryOperator* index =  +	    BinaryOperator::create( Instruction::Add, m, IOne ); +	bb->getInstList().push_back( index ); +	LoadInst* Xm = cast<LoadInst>( stack_top(bb, index ) ); +	BinaryOperator* n_plus_1 =  +	    BinaryOperator::create( Instruction::Add, n, IOne ); +	bb->getInstList().push_back( n_plus_1 ); +	decr_stack_index( bb, n_plus_1 ); +	replace_top( bb, Xm ); +	break; +    } +    case MALLOC : // n -- p +    { +	if (echo) bb->setName("MALLOC"); +	// Get the number of bytes to mallocate +	LoadInst* op1 = cast<LoadInst>( pop_integer(bb) ); + +	// Make sure its a UIntTy +	CastInst* caster = new CastInst( op1, Type::UIntTy ); +	bb->getInstList().push_back( caster ); + +	// Allocate the bytes +	MallocInst* mi = new MallocInst( Type::SByteTy, caster ); +	bb->getInstList().push_back( mi ); + +	// Push the pointer +	push_value( bb, mi ); +	break; +    } +    case FREE :  // p -- +    { +	if (echo) bb->setName("FREE"); +	// Pop the value off the stack +	CastInst* ptr = cast<CastInst>( pop_string(bb) ); + +	// Free the memory +	FreeInst* fi = new FreeInst( ptr ); +	bb->getInstList().push_back( fi ); + +	break; +    } +    case GET : // p w1 -- p w2 +    { +	if (echo) bb->setName("GET"); +	// Get the character index +	LoadInst* op1 = cast<LoadInst>( stack_top(bb) ); +	CastInst* chr_idx = new CastInst( op1, Type::LongTy ); +	bb->getInstList().push_back( chr_idx ); + +	// Get the String pointer +	CastInst* ptr = cast<CastInst>( stack_top_string(bb,One) ); + +	// Get address of op1'th element of the string +	std::vector<Value*> indexVec; +	indexVec.push_back( chr_idx ); +	GetElementPtrInst* gep = new GetElementPtrInst( ptr, indexVec ); +	bb->getInstList().push_back( gep ); + +	// Get the value and push it +	LoadInst* loader = new LoadInst( gep ); +	bb->getInstList().push_back( loader ); +	CastInst* caster = new CastInst( loader, Type::IntTy ); +	bb->getInstList().push_back( caster ); + +	// Push the result back on stack +	replace_top( bb, caster ); + +	break; +    } +    case PUT : // p w2 w1  -- p +    { +	if (echo) bb->setName("PUT"); + +	// Get the value to put +	LoadInst* w1 = cast<LoadInst>( pop_integer(bb) ); + +	// Get the character index +	LoadInst* w2 = cast<LoadInst>( pop_integer(bb) ); +	CastInst* chr_idx = new CastInst( w2, Type::LongTy ); +	bb->getInstList().push_back( chr_idx ); + +	// Get the String pointer +	CastInst* ptr = cast<CastInst>( stack_top_string(bb) ); + +	// Get address of op2'th element of the string +	std::vector<Value*> indexVec; +	indexVec.push_back( chr_idx ); +	GetElementPtrInst* gep = new GetElementPtrInst( ptr, indexVec ); +	bb->getInstList().push_back( gep ); + +	// Cast the value and put it +	CastInst* caster = new CastInst( w1, Type::SByteTy ); +	bb->getInstList().push_back( caster ); +	StoreInst* storer = new StoreInst( caster, gep ); +	bb->getInstList().push_back( storer ); + +	break; +    } +    case RECURSE :  +    { +	if (echo) bb->setName("RECURSE"); +	std::vector<Value*> params; +	CallInst* call_inst = new CallInst( TheFunction, params ); +	bb->getInstList().push_back( call_inst ); +	break; +    } +    case RETURN :  +    { +	if (echo) bb->setName("RETURN"); +	bb->getInstList().push_back( new ReturnInst() ); +	break; +    } +    case EXIT :  +    { +	if (echo) bb->setName("EXIT"); +	// Get the result value +	LoadInst* op1 = cast<LoadInst>(pop_integer(bb)); + +	// Call exit(3) +	std::vector<Value*> params; +	params.push_back(op1); +	CallInst* call_inst = new CallInst( TheExit, params ); +	bb->getInstList().push_back( call_inst ); +	break; +    } +    case TAB : +    { +	if (echo) bb->setName("TAB"); +	// Get the format string for a character +	std::vector<Value*> indexVec; +	indexVec.push_back( Zero ); +	indexVec.push_back( Zero ); +	GetElementPtrInst* format_gep =  +	    new GetElementPtrInst( ChrFormat, indexVec ); +	bb->getInstList().push_back( format_gep ); + +	// Get the character to print (a newline) +	ConstantSInt* newline = ConstantSInt::get(Type::IntTy,  +	    static_cast<int>('\t')); + +	// Call printf +	std::vector<Value*> args; +	args.push_back( format_gep ); +	args.push_back( newline ); +	bb->getInstList().push_back( new CallInst( ThePrintf, args ) ); +	break; +    } +    case SPACE :  +    { +	if (echo) bb->setName("SPACE"); +	// Get the format string for a character +	std::vector<Value*> indexVec; +	indexVec.push_back( Zero ); +	indexVec.push_back( Zero ); +	GetElementPtrInst* format_gep =  +	    new GetElementPtrInst( ChrFormat, indexVec ); +	bb->getInstList().push_back( format_gep ); + +	// Get the character to print (a newline) +	ConstantSInt* newline = ConstantSInt::get(Type::IntTy,  +	    static_cast<int>(' ')); + +	// Call printf +	std::vector<Value*> args; +	args.push_back( format_gep ); +	args.push_back( newline ); +	bb->getInstList().push_back( new CallInst( ThePrintf, args ) ); +	break; +    } +    case CR :  +    { +	if (echo) bb->setName("CR"); +	// Get the format string for a character +	std::vector<Value*> indexVec; +	indexVec.push_back( Zero ); +	indexVec.push_back( Zero ); +	GetElementPtrInst* format_gep =  +	    new GetElementPtrInst( ChrFormat, indexVec ); +	bb->getInstList().push_back( format_gep ); + +	// Get the character to print (a newline) +	ConstantSInt* newline = ConstantSInt::get(Type::IntTy,  +	    static_cast<int>('\n')); + +	// Call printf +	std::vector<Value*> args; +	args.push_back( format_gep ); +	args.push_back( newline ); +	bb->getInstList().push_back( new CallInst( ThePrintf, args ) ); +	break; +    } +    case IN_STR :  +    { +	if (echo) bb->setName("IN_STR"); +	// Make room for the value result +	incr_stack_index(bb); +	GetElementPtrInst* gep_value =  +	    cast<GetElementPtrInst>(get_stack_pointer(bb)); +	CastInst* caster =  +	    new CastInst( gep_value, PointerType::get( Type::SByteTy ) ); + +	// Make room for the count result +	incr_stack_index(bb); +	GetElementPtrInst* gep_count =  +	    cast<GetElementPtrInst>(get_stack_pointer(bb)); + +	// Call scanf(3) +	std::vector<Value*> args; +	args.push_back( InStrFormat ); +	args.push_back( caster ); +	CallInst* scanf = new CallInst( TheScanf, args ); +	bb->getInstList().push_back( scanf ); + +	// Store the result +	bb->getInstList().push_back( new StoreInst( scanf, gep_count ) ); +	break; +    } +    case IN_NUM :  +    { +	if (echo) bb->setName("IN_NUM"); +	// Make room for the value result +	incr_stack_index(bb); +	GetElementPtrInst* gep_value =  +	    cast<GetElementPtrInst>(get_stack_pointer(bb)); + +	// Make room for the count result +	incr_stack_index(bb); +	GetElementPtrInst* gep_count =  +	    cast<GetElementPtrInst>(get_stack_pointer(bb)); + +	// Call scanf(3) +	std::vector<Value*> args; +	args.push_back( InStrFormat ); +	args.push_back( gep_value ); +	CallInst* scanf = new CallInst( TheScanf, args ); +	bb->getInstList().push_back( scanf ); + +	// Store the result +	bb->getInstList().push_back( new StoreInst( scanf, gep_count ) ); +	break; +    } +    case IN_CHAR : +    { +	if (echo) bb->setName("IN_CHAR"); +	// Make room for the value result +	incr_stack_index(bb); +	GetElementPtrInst* gep_value =  +	    cast<GetElementPtrInst>(get_stack_pointer(bb)); + +	// Make room for the count result +	incr_stack_index(bb); +	GetElementPtrInst* gep_count =  +	    cast<GetElementPtrInst>(get_stack_pointer(bb)); + +	// Call scanf(3) +	std::vector<Value*> args; +	args.push_back( InChrFormat ); +	args.push_back( gep_value ); +	CallInst* scanf = new CallInst( TheScanf, args ); +	bb->getInstList().push_back( scanf ); + +	// Store the result +	bb->getInstList().push_back( new StoreInst( scanf, gep_count ) ); +	break; +    } +    case OUT_STR :  +    { +	if (echo) bb->setName("OUT_STR"); +	LoadInst* op1 = cast<LoadInst>(stack_top(bb)); + +	// Get the address of the format string +	std::vector<Value*> indexVec; +	indexVec.push_back( Zero ); +	indexVec.push_back( Zero ); +	GetElementPtrInst* format_gep =  +	    new GetElementPtrInst( StrFormat, indexVec ); +	bb->getInstList().push_back( format_gep ); +	// Build function call arguments +	std::vector<Value*> args; +	args.push_back( format_gep ); +	args.push_back( op1 ); +	// Call printf +	bb->getInstList().push_back( new CallInst( ThePrintf, args ) ); +	break; +    } +    case OUT_NUM :  +    { +	if (echo) bb->setName("OUT_NUM"); +	// Pop the numeric operand off the stack +	LoadInst* op1 = cast<LoadInst>(stack_top(bb)); + +	// Get the address of the format string +	std::vector<Value*> indexVec; +	indexVec.push_back( Zero ); +	indexVec.push_back( Zero ); +	GetElementPtrInst* format_gep =  +	    new GetElementPtrInst( NumFormat, indexVec ); +	bb->getInstList().push_back( format_gep ); + +	// Build function call arguments +	std::vector<Value*> args; +	args.push_back( format_gep ); +	args.push_back( op1 ); + +	// Call printf +	bb->getInstList().push_back( new CallInst( ThePrintf, args ) ); +	break; +    } +    case OUT_CHAR : +    { +	if (echo) bb->setName("OUT_CHAR"); +	// Pop the character operand off the stack +	LoadInst* op1 = cast<LoadInst>(stack_top(bb)); + +	// Get the address of the format string +	std::vector<Value*> indexVec; +	indexVec.push_back( Zero ); +	indexVec.push_back( Zero ); +	GetElementPtrInst* format_gep =  +	    new GetElementPtrInst( ChrFormat, indexVec ); +	bb->getInstList().push_back( format_gep ); + +	// Build function call arguments +	std::vector<Value*> args; +	args.push_back( format_gep ); +	args.push_back( op1 ); +	// Call printf +	bb->getInstList().push_back( new CallInst( ThePrintf, args ) ); +	break; +    } +    default : +    { +	ThrowException(std::string("Compiler Error: Unhandled token #")); +    } +    } + +    // Return the basic block +    return bb; +} diff --git a/projects/Stacker/lib/compiler/StackerCompiler.h b/projects/Stacker/lib/compiler/StackerCompiler.h new file mode 100644 index 0000000..9e35fa8 --- /dev/null +++ b/projects/Stacker/lib/compiler/StackerCompiler.h @@ -0,0 +1,224 @@ +//===-- StackerCompiler.h - Interface to the Stacker Compiler ---*- C++ -*-===// +//  +//                     The LLVM Compiler Infrastructure +// +// This file was developed by Reid Spencer and donated to the LLVM research  +// group and is distributed under the University of Illinois Open Source  +// License. See LICENSE.TXT for details. +//  +//===----------------------------------------------------------------------===// +// +//  This header file defines the various variables that are shared among the  +//  different components of the parser... +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_STACKERCOMPILER_H +#define LLVM_STACKERCOMPILER_H + +#include <llvm/Constants.h> +#include <llvm/DerivedTypes.h> +#include <llvm/Function.h> +#include <llvm/Instruction.h> +#include <llvm/Module.h> +#include <llvm/Assembly/Parser.h> +#include <Support/StringExtras.h> + +using namespace llvm; + +// Global variables exported from the lexer... +extern std::FILE *Stackerin; +extern int Stackerlineno; +extern char* Stackertext; +extern int Stackerleng; + +/// @brief This class provides the Compiler for the Stacker language.  +///  +/// The main method to call is \c compile. The other methods are +/// all internal to the compiler and protected. In general the  +/// handle_* methods are called by the BISON generated parser +/// (see StackerParser.y). The methods returning Instruction* all +/// produce some snippet of code to manipulate the stack in some +/// way. These functions are just conveniences as they are used +/// often by the compiler. +class StackerCompiler +{ +    /// @name Constructors and Operators +    /// @{ +    public: +	/// Default Constructor +	StackerCompiler(); + +	/// Destructor +	~StackerCompiler(); +    private: +	/// Do not copy StackerCompilers +	StackerCompiler(const StackerCompiler&); + +	/// Do not copy StackerCompilers. +	StackerCompiler& operator=(const StackerCompiler& ); + +    /// @} +    /// @name High Level Interface +    /// @{ +    public: +	/// @brief Compile a single file to LLVM bytecode. +	/// +	/// To use the StackerCompiler, just create one on +	/// the stack and call this method. +	Module* compile(  +	    const std::string& filename, ///< File to compile +	    bool echo, ///< Causes compiler to echo output +	    size_t stack_size ); ///< Size of generated stack +    /// @} +    /// @name Accessors +    /// @{ +    public: +	/// @brief Returns the name of the file being compiled. +	std::string& filename() { return CurFilename; } + +    /// @} +    /// @name Parse Handling Methods +    /// @{ +    private: +	/// Allow only the parser to access these methods. No +	/// one else should call them. +	friend int Stackerparse(); + +	/// @brief Handle the start of a module +	Module* handle_module_start(); + +	/// @brief Handle the end of a module +	/// @param mod The module we're defining. +	Module* handle_module_end( Module* mod ); + +	/// @brief Handle the start of a list of definitions +	Module* handle_definition_list_start( ); + +	/// @brief Handle the end of a list of definitions +	/// @param mod The module we're constructing +	/// @param definition A definition (function) to add to the module +	Module* handle_definition_list_end( Module* mod, Function* definition ); + +	/// @brief Handle creation of the MAIN definition +	/// @param func The function to be used as the MAIN definition +	Function* handle_main_definition( Function* func ); + +	/// @brief Handle a forward definition +	/// @param name The name of the definition being declared +	Function* handle_forward( char* name ); + +	/// @brief Handle a general definition +	/// @param name The name of the definition being defined +	/// @param func The Function definition. +	Function* handle_definition( char* name, Function* func ); + +	/// @brief Handle the start of a definition's word list +	Function* handle_word_list_start(); + +	/// @brief Handle the end of a definition's word list +	/// @param func The function to which the basic block is added +	/// @param next The block to add to the function +	Function* handle_word_list_end( Function* func, BasicBlock* next ); + +	/// @brief Handle an if statement, possibly without an else +	/// @brief ifTrue The block to execute if true +	/// @brief ifFalse The optional block to execute if false +	BasicBlock* handle_if( char* ifTrue, char* ifFalse = 0 ); + +	/// @brief Handle a while statement +	/// @brief todo The block to repeatedly execute +	BasicBlock* handle_while( char* todo ); + +	/// @brief Handle an identifier to call the identified definition +	/// @param name The name of the identifier to be called. +	BasicBlock* handle_identifier( char * name ); + +	/// @brief Handle the push of a string onto the stack +	/// @param value The string to be pushed. +	BasicBlock* handle_string( char * value ); + +	/// @brief Handle the push of an integer onto the stack. +	/// @param value The integer value to be pushed. +	BasicBlock* handle_integer( const int32_t value ); + +	/// @brief Handle one of the reserved words (given as a token) +	BasicBlock* handle_word( int tkn ); + +    /// @} +    /// @name Utility functions +    /// @{ +    public: +        /// @brief Throws an exception to indicate an error +        /// @param message The message to be output +	/// @param line Override for the current line no +	static inline void ThrowException( const std::string &message,  +		int line = -1) 	     +	{ +	  if (line == -1) line = Stackerlineno; +	  // TODO: column number in exception +	  throw ParseException(TheInstance->CurFilename, message, line); +	} +    private: +	/// @brief Generate code to increment the stack index +	Instruction* incr_stack_index( BasicBlock* bb, Value* ); +	/// @brief Generate code to decrement the stack index. +	Instruction* decr_stack_index( BasicBlock* bb, Value* ); +	/// @brief Generate code to dereference the top of stack. +	Instruction* get_stack_pointer( BasicBlock* bb, Value* ); +	/// @brief Generate code to push any value onto the stack. +	Instruction* push_value( BasicBlock* bb, Value* value ); +	/// @brief Generate code to push a constant integer onto the stack. +	Instruction* push_integer( BasicBlock* bb, int32_t value ); +	/// @brief Generate code to pop an integer off the stack. +	Instruction* pop_integer( BasicBlock* bb ); +	/// @brief Generate code to push a string pointer onto the stack. +	Instruction* push_string( BasicBlock* bb, const char* value ); +	/// @brief Generate code to pop a string pointer off the stack. +	Instruction* pop_string( BasicBlock* bb ); +	/// @brief Generate code to get the top stack element. +	Instruction* stack_top( BasicBlock* bb, Value* index ); +	/// @brief Generate code to get the top stack element as a string. +	Instruction* stack_top_string( BasicBlock* bb, Value* index ); +	/// @brief Generate code to replace the top element of the stack. +	Instruction* replace_top( BasicBlock* bb, Value* new_top, Value* index); + +    /// @} +    /// @name Data Members (used during parsing) +    /// @{ +    public: +        static StackerCompiler*	TheInstance;	///< The instance for the parser + +    private: +	std::string 		CurFilename;	///< Current file name +	Module* 		TheModule; 	///< Module instance we'll build +        Function*		TheFunction;	///< Function we're building +	FunctionType* 		DefinitionType; ///< FT for Definitions +	GlobalVariable*		TheStack;	///< For referencing _stack_ +	GlobalVariable*		TheIndex;	///< For referencing _index_ +	Function*		TheScanf;	///< External input function +	Function*		ThePrintf;	///< External output function +	Function*		TheExit;	///< External exit function +	GlobalVariable*		StrFormat;	///< Format for strings +	GlobalVariable*		NumFormat;	///< Format for numbers +	GlobalVariable*		ChrFormat;	///< Format for chars +	GlobalVariable*		InStrFormat;	///< Format for input strings +	GlobalVariable*		InNumFormat;	///< Format for input numbers +	GlobalVariable*		InChrFormat;	///< Format for input chars +	ConstantInt*		Zero;		///< long constant 0 +	ConstantInt*		One;		///< long constant 1 +	ConstantInt*		Two;		///< long constant 2 +	ConstantInt*		Three;		///< long constant 3 +	ConstantInt*		Four;		///< long constant 4 +	ConstantInt*		Five;		///< long constant 5 +	ConstantInt*		IZero;		///< int constant 0 +	ConstantInt*		IOne;		///< int constant 1 +	ConstantInt*		ITwo;		///< int constant 2 +	std::vector<Value*> 	no_arguments;	///< no arguments for Stacker +	bool 			echo;		///< Echo flag +	size_t			stack_size;	///< Size of stack to gen. +	ArrayType*		stack_type;	///< The type of the stack +    /// @} +}; + +#endif diff --git a/projects/Stacker/lib/compiler/StackerParser.y b/projects/Stacker/lib/compiler/StackerParser.y new file mode 100644 index 0000000..3c82a86 --- /dev/null +++ b/projects/Stacker/lib/compiler/StackerParser.y @@ -0,0 +1,190 @@ +//===-- llvmAsmParser.y - Parser for llvm assembly files --------*- C++ -*-===// +//  +//                     The LLVM Compiler Infrastructure +// +// This file was developed by the LLVM research group and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +//  +//===----------------------------------------------------------------------===// +// +//  This file implements the bison parser for LLVM assembly languages files. +// +//===----------------------------------------------------------------------===// + +%debug + +%{ +#include "StackerCompiler.h" +#include "llvm/SymbolTable.h" +#include "llvm/Module.h" +#include "llvm/iTerminators.h" +#include "llvm/iMemory.h" +#include "llvm/iOperators.h" +#include "llvm/iPHINode.h" +#include "Support/STLExtras.h" +#include "Support/DepthFirstIterator.h" +#include <list> +#include <utility> +#include <algorithm> + +#define YYERROR_VERBOSE 1 +#define SCI StackerCompiler::TheInstance + +int yyerror(const char *ErrorMsg); // Forward declarations to prevent "implicit +int yylex();                       // declaration" of xxx warnings. +int yyparse(); + +%} + +%union  +{ +  llvm::Module*		ModuleVal; +  llvm::Function* 	FunctionVal; +  llvm::BasicBlock*	BasicBlockVal; +  uint32_t              IntegerVal; +  char*                 StringVal; +} + +/* Typed Productions */ +%type <ModuleVal>	Module DefinitionList +%type <FunctionVal>	Definition ForwardDef ColonDef MainDef +%type <FunctionVal>	WordList +%type <BasicBlockVal>	Word + +/* Typed Tokens */ +%token <IntegerVal>	INTEGER +%token <StringVal>	STRING IDENTIFIER + +/* Terminal Tokens */ +%token 			SEMI COLON FORWARD MAIN DUMP +%token  		TRUE FALSE LESS MORE LESS_EQUAL MORE_EQUAL NOT_EQUAL EQUAL +%token 			PLUS MINUS INCR DECR MULT DIV MODULUS NEGATE ABS MIN MAX STAR_SLASH  +%token 			AND OR XOR LSHIFT RSHIFT  +%token 			DROP DROP2 NIP NIP2 DUP DUP2 SWAP SWAP2	OVER OVER2 ROT ROT2  +%token			RROT RROT2 TUCK TUCK2 ROLL PICK SELECT +%token 			MALLOC FREE GET PUT +%token 			IF ELSE ENDIF WHILE END RECURSE RETURN EXIT +%token 			TAB SPACE CR IN_STR IN_NUM IN_CHAR OUT_STR OUT_NUM OUT_CHAR + +/* Start Token */ +%start Module + +%% + +/* A module is just a DefinitionList */ +Module 		: 				{ SCI->handle_module_start( ); }  +	 	DefinitionList 			{ $$ = SCI->handle_module_end( $2 ); } ; + +/* A Definitionlist is just a sequence of definitions */ +DefinitionList	: DefinitionList Definition 	{ $$ = SCI->handle_definition_list_end( $1, $2 ); } +		| /* empty */ 			{ $$ = SCI->handle_definition_list_start(); } ; + +/* A definition can be one of three flavors */ +Definition 	: ForwardDef 			{ $$ = $1; } +	   	| ColonDef			{ $$ = $1; } +	   	| MainDef			{ $$ = $1; } ; + +/* Forward definitions just introduce a name */ +ForwardDef : FORWARD IDENTIFIER SEMI 		{ $$ = SCI->handle_forward( $2 ); } ; + +/* The main definition has to generate additional code so we treat it specially */ +MainDef : COLON MAIN WordList SEMI		{ $$ = SCI->handle_main_definition($3); } ; + +/* Regular definitions have a name and a WordList */ +ColonDef : COLON IDENTIFIER WordList SEMI 	{ $$ = SCI->handle_definition( $2, $3 ); } ; + +/* A WordList is just a sequence of words */ +WordList : WordList Word 			{ $$ = SCI->handle_word_list_end( $1, $2 ); }  +	 | /* empty */				{ $$ = SCI->handle_word_list_start() } ; + +/* A few "words" have a funky syntax */ +/* FIXME: The body of compound words can currently only be function calls */ +/* This is not acceptable, it should be a WordList, but that produces a Function */ +/* Which is hard to merge into the function the compound statement is working on */ +Word : IF IDENTIFIER ELSE IDENTIFIER ENDIF	{ $$ = SCI->handle_if( $2, $4 ); }  +     | IF IDENTIFIER ENDIF			{ $$ = SCI->handle_if( $2 ); }  +     | WHILE IDENTIFIER END			{ $$ = SCI->handle_while( $2 ); } ; + +/* A few words are handled specially */ +Word : IDENTIFIER 				{ $$ = SCI->handle_identifier( $1 ); } ; +Word : STRING 					{ $$ = SCI->handle_string( $1 ); } ; +Word : INTEGER 					{ $$ = SCI->handle_integer( $1 ); } ; + +/* Everything else is a terminal symbol and goes to handle_word */ +Word : TRUE					{ $$ = SCI->handle_word( TRUE ); } ; +Word : FALSE					{ $$ = SCI->handle_word( FALSE ); } ; +Word : LESS					{ $$ = SCI->handle_word( LESS ); } ; +Word : MORE					{ $$ = SCI->handle_word( MORE ); } ; +Word : LESS_EQUAL				{ $$ = SCI->handle_word( LESS_EQUAL ); } ; +Word : MORE_EQUAL				{ $$ = SCI->handle_word( MORE_EQUAL ); } ; +Word : NOT_EQUAL				{ $$ = SCI->handle_word( NOT_EQUAL ); } ; +Word : EQUAL					{ $$ = SCI->handle_word( EQUAL ); } ; +Word : PLUS					{ $$ = SCI->handle_word( PLUS ); } ; +Word : MINUS					{ $$ = SCI->handle_word( MINUS ); } ; +Word : INCR					{ $$ = SCI->handle_word( INCR ); } ; +Word : DECR					{ $$ = SCI->handle_word( DECR ); } ; +Word : MULT					{ $$ = SCI->handle_word( MULT ); } ; +Word : DIV					{ $$ = SCI->handle_word( DIV ); } ; +Word : MODULUS					{ $$ = SCI->handle_word( MODULUS ); } ; +Word : NEGATE					{ $$ = SCI->handle_word( NEGATE ); } ; +Word : ABS					{ $$ = SCI->handle_word( ABS ); } ; +Word : MIN					{ $$ = SCI->handle_word( MIN ); } ; +Word : MAX					{ $$ = SCI->handle_word( MAX ); } ; +Word : STAR_SLASH				{ $$ = SCI->handle_word( STAR_SLASH ); } ; +Word : AND					{ $$ = SCI->handle_word( AND ); } ; +Word : OR					{ $$ = SCI->handle_word( OR ); } ; +Word : XOR					{ $$ = SCI->handle_word( XOR ); } ; +Word : LSHIFT					{ $$ = SCI->handle_word( LSHIFT ); } ; +Word : RSHIFT					{ $$ = SCI->handle_word( RSHIFT ); } ; +Word : DROP					{ $$ = SCI->handle_word( DROP ); } ; +Word : DROP2					{ $$ = SCI->handle_word( DROP2 ); } ; +Word : NIP					{ $$ = SCI->handle_word( NIP ); } ; +Word : NIP2					{ $$ = SCI->handle_word( NIP2 ); } ; +Word : DUP					{ $$ = SCI->handle_word( DUP ); } ; +Word : DUP2					{ $$ = SCI->handle_word( DUP2 ); } ; +Word : SWAP					{ $$ = SCI->handle_word( SWAP ); } ; +Word : SWAP2					{ $$ = SCI->handle_word( SWAP2 ); } ; +Word : OVER					{ $$ = SCI->handle_word( OVER ); } ; +Word : OVER2					{ $$ = SCI->handle_word( OVER2 ); } ; +Word : ROT					{ $$ = SCI->handle_word( ROT ); } ; +Word : ROT2					{ $$ = SCI->handle_word( ROT2 ); } ; +Word : RROT					{ $$ = SCI->handle_word( RROT ); } ; +Word : RROT2					{ $$ = SCI->handle_word( RROT2 ); } ; +Word : TUCK					{ $$ = SCI->handle_word( TUCK ); } ; +Word : TUCK2					{ $$ = SCI->handle_word( TUCK2 ); } ; +Word : ROLL					{ $$ = SCI->handle_word( ROLL ); } ; +Word : PICK					{ $$ = SCI->handle_word( PICK ); } ; +Word : SELECT					{ $$ = SCI->handle_word( SELECT ); } ; +Word : MALLOC					{ $$ = SCI->handle_word( MALLOC ); } ; +Word : FREE					{ $$ = SCI->handle_word( FREE ); } ; +Word : GET					{ $$ = SCI->handle_word( GET ); } ; +Word : PUT					{ $$ = SCI->handle_word( PUT ); } ; +Word : RECURSE					{ $$ = SCI->handle_word( RECURSE ); } ; +Word : RETURN					{ $$ = SCI->handle_word( RETURN ); } ; +Word : EXIT					{ $$ = SCI->handle_word( EXIT ); } ; +Word : TAB					{ $$ = SCI->handle_word( TAB ); }; +Word : SPACE					{ $$ = SCI->handle_word( SPACE ); } ; +Word : CR					{ $$ = SCI->handle_word( CR ); } ; +Word : IN_STR					{ $$ = SCI->handle_word( IN_STR ); } ; +Word : IN_NUM					{ $$ = SCI->handle_word( IN_NUM ); } ; +Word : IN_CHAR					{ $$ = SCI->handle_word( IN_CHAR ); } ; +Word : OUT_STR					{ $$ = SCI->handle_word( OUT_STR ); } ; +Word : OUT_NUM					{ $$ = SCI->handle_word( OUT_NUM ); } ; +Word : OUT_CHAR					{ $$ = SCI->handle_word( OUT_CHAR ); } ; +Word : DUMP					{ $$ = SCI->handle_word( DUMP ); } ; + +%% + +/* Handle messages a little more nicely than the default yyerror */ +int yyerror(const char *ErrorMsg) { +  std::string where  +    = std::string((SCI->filename() == "-") ? std::string("<stdin>") : SCI->filename()) +                  + ":" + utostr((unsigned) Stackerlineno ) + ": "; +  std::string errMsg = std::string(ErrorMsg) + "\n" + where + " while reading "; +  if (yychar == YYEMPTY) +    errMsg += "end-of-file."; +  else +    errMsg += "token: '" + std::string(Stackertext, Stackerleng) + "'"; +  StackerCompiler::ThrowException(errMsg); +  return 0; +} | 
