From: Chris Lattner Date: Sun, 23 Nov 2003 17:52:55 +0000 (+0000) Subject: Initial stacker checkin X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=f608e853232b324ed4d3de238e47c9999504585b;p=oota-llvm.git Initial stacker checkin git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@10178 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/projects/Stacker/lib/compiler/Lexer.l b/projects/Stacker/lib/compiler/Lexer.l new file mode 100644 index 00000000000..6087f883e5c --- /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 +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 00000000000..4c89ca8468a --- /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 00000000000..5f13cbb52f9 --- /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 00000000000..6ebcae9b365 --- /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 +#include +#include +#include +#include +#include +#include "StackerCompiler.h" +#include "StackerParser.h" +#include + +// 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 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 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( + 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( + 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( + 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( + 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( + 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( + 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 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( 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 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( 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 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 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 -- w2setName("LESS"); + LoadInst* op1 = cast(pop_integer(bb)); + LoadInst* op2 = cast(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(pop_integer(bb)); + LoadInst* op2 = cast(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(pop_integer(bb)); + LoadInst* op2 = cast(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(pop_integer(bb)); + LoadInst* op2 = cast(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(pop_integer(bb)); + LoadInst* op2 = cast(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(pop_integer(bb)); + LoadInst* op2 = cast(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(pop_integer(bb)); + LoadInst* op2 = cast(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(pop_integer(bb)); + LoadInst* op2 = cast(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(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(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(pop_integer(bb)); + LoadInst* op2 = cast(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(pop_integer(bb)); + LoadInst* op2 = cast(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(pop_integer(bb)); + LoadInst* op2 = cast(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(pop_integer(bb)); + LoadInst* op2 = cast(pop_integer(bb)); + LoadInst* op3 = cast(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(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(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( 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 -- (w2setName("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(pop_integer(bb)); + LoadInst* op2 = cast(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(pop_integer(bb)); + LoadInst* op2 = cast(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(pop_integer(bb)); + LoadInst* op2 = cast(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(pop_integer(bb)); + LoadInst* op2 = cast(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(pop_integer(bb)); + LoadInst* op2 = cast(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<setName("SHL"); + LoadInst* op1 = cast(pop_integer(bb)); + LoadInst* op2 = cast(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(pop_integer(bb)); + LoadInst* op2 = cast(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( 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( stack_top( bb ) ); + LoadInst* w3 = cast( 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( stack_top( bb ) ); + push_value( bb, w ); + break; + } + case DUP2: // w1 w2 -- w1 w2 w1 w2 + { + if (echo) bb->setName("DUP2"); + LoadInst* w2 = cast( stack_top(bb) ); + LoadInst* w1 = cast( 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( stack_top( bb ) ); + LoadInst* w1 = cast( 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( stack_top( bb ) ); + LoadInst* w3 = cast( stack_top( bb, One ) ); + LoadInst* w2 = cast( stack_top( bb, Two ) ); + LoadInst* w1 = cast( 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( 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( stack_top( bb, Two ) ); + LoadInst* w1 = cast( 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( stack_top( bb ) ); + LoadInst* w2 = cast( stack_top( bb, One ) ); + LoadInst* w1 = cast( 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( stack_top( bb ) ); + LoadInst* w5 = cast( stack_top( bb, One ) ); + LoadInst* w4 = cast( stack_top( bb, Two ) ); + LoadInst* w3 = cast( stack_top( bb, Three) ); + LoadInst* w2 = cast( stack_top( bb, Four ) ); + LoadInst* w1 = cast( 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( stack_top( bb ) ); + LoadInst* w2 = cast( stack_top( bb, One ) ); + LoadInst* w1 = cast( 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( stack_top( bb ) ); + LoadInst* w5 = cast( stack_top( bb, One ) ); + LoadInst* w4 = cast( stack_top( bb, Two ) ); + LoadInst* w3 = cast( stack_top( bb, Three) ); + LoadInst* w2 = cast( stack_top( bb, Four ) ); + LoadInst* w1 = cast( 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( stack_top( bb ) ); + LoadInst* w1 = cast( 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( stack_top( bb ) ); + LoadInst* w3 = cast( stack_top( bb, One ) ); + LoadInst* w2 = cast( stack_top( bb, Two ) ); + LoadInst* w1 = cast( 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( stack_top( bb ) ); + BinaryOperator* addop = + BinaryOperator::create( Instruction::Add, n, IOne ); + bb->getInstList().push_back( addop ); + LoadInst* x0 = cast( 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( stack_top(bb) ); + LoadInst* n = cast( stack_top(bb, One) ); + BinaryOperator* index = + BinaryOperator::create( Instruction::Add, m, IOne ); + bb->getInstList().push_back( index ); + LoadInst* Xm = cast( 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( 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( 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( stack_top(bb) ); + CastInst* chr_idx = new CastInst( op1, Type::LongTy ); + bb->getInstList().push_back( chr_idx ); + + // Get the String pointer + CastInst* ptr = cast( stack_top_string(bb,One) ); + + // Get address of op1'th element of the string + std::vector 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( pop_integer(bb) ); + + // Get the character index + LoadInst* w2 = cast( pop_integer(bb) ); + CastInst* chr_idx = new CastInst( w2, Type::LongTy ); + bb->getInstList().push_back( chr_idx ); + + // Get the String pointer + CastInst* ptr = cast( stack_top_string(bb) ); + + // Get address of op2'th element of the string + std::vector 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 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(pop_integer(bb)); + + // Call exit(3) + std::vector 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 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('\t')); + + // Call printf + std::vector 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 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(' ')); + + // Call printf + std::vector 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 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('\n')); + + // Call printf + std::vector 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(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(get_stack_pointer(bb)); + + // Call scanf(3) + std::vector 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(get_stack_pointer(bb)); + + // Make room for the count result + incr_stack_index(bb); + GetElementPtrInst* gep_count = + cast(get_stack_pointer(bb)); + + // Call scanf(3) + std::vector 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(get_stack_pointer(bb)); + + // Make room for the count result + incr_stack_index(bb); + GetElementPtrInst* gep_count = + cast(get_stack_pointer(bb)); + + // Call scanf(3) + std::vector 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(stack_top(bb)); + + // Get the address of the format string + std::vector 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 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(stack_top(bb)); + + // Get the address of the format string + std::vector 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 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(stack_top(bb)); + + // Get the address of the format string + std::vector 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 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 00000000000..9e35fa81441 --- /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 +#include +#include +#include +#include +#include +#include + +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 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 00000000000..3c82a86ea01 --- /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 +#include +#include + +#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 Module DefinitionList +%type Definition ForwardDef ColonDef MainDef +%type WordList +%type Word + +/* Typed Tokens */ +%token INTEGER +%token 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("") : 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; +}