beebasm

changeset 5:bf4ee211ca83

BeebASM v0.03 - first released Jan 07 2008 09:14:08
author Samwise <samwise@bagshot-row.org>
date Sun May 02 12:04:21 2010 +0100
parents 03efcda85f5e
children 72e5df92f741
files about.txt beebasm.exe demo.asm demo.ssd src/Makefile src/Makefile.inc src/asmexception.h src/assemble.cpp src/commands.cpp src/expression.cpp src/lineparser.h src/main.cpp src/objectcode.cpp src/objectcode.h src/sourcefile.cpp src/sourcefile.h src/symboltable.cpp src/symboltable.h
diffstat 18 files changed, 518 insertions(+), 30 deletions(-) [+]
line diff
     1.1 --- a/about.txt	Sun May 02 11:57:59 2010 +0100
     1.2 +++ b/about.txt	Sun May 02 12:04:21 2010 +0100
     1.3 @@ -1,6 +1,6 @@
     1.4  *******************************************************************************
     1.5  *                                                                             *
     1.6 -*                                   BeebAsm                                   *
     1.7 +*                               BeebAsm V0.04                                 *
     1.8  *                                                                             *
     1.9  *             A portable 6502 assembler with BBC Micro style syntax           *
    1.10  *                                                                             *
    1.11 @@ -154,6 +154,10 @@
    1.12  
    1.13  Verbose output.  Assembled code will be output to the screen.
    1.14  
    1.15 +-d
    1.16 +
    1.17 +Dumps all symbols in Swift-compatible format after assembly
    1.18 +
    1.19  
    1.20  
    1.21  
    1.22 @@ -210,6 +214,10 @@
    1.23  SGN(val)           Return -1, 0 or 1, depending on the sign of the argument
    1.24  RND(val)           RND(1) returns a random number between 0 and 1
    1.25                     RND(n) returns an integer between 0 and n-1
    1.26 +NOT(val)           Return the bitwise 1's complement of val
    1.27 +LOG(val)           Return the base 10 log of val
    1.28 +LN(val)            Return the natural log of val
    1.29 +EXP(val)           Return e raised to the power of val
    1.30  
    1.31  Also, some constants are defined:
    1.32  
    1.33 @@ -247,6 +255,12 @@
    1.34  reserve a space of a fixed size in the code.
    1.35  
    1.36  
    1.37 +SKIPTO <addr>
    1.38 +
    1.39 +Moves the address pointer to the specified address.  An error is generated if
    1.40 +this address is behind the current address pointer.
    1.41 +
    1.42 +
    1.43  ALIGN <alignment>
    1.44  
    1.45  Used to align the address pointer to the next boundary, e.g. use ALIGN &100 to
    1.46 @@ -259,6 +273,11 @@
    1.47  Includes the specified source file in the code at this point.
    1.48  
    1.49  
    1.50 +INCBIN "filename"
    1.51 +
    1.52 +Includes the specified binary file in the object code at this point.
    1.53 +
    1.54 +
    1.55  EQUB a [, b, c, ...]
    1.56  
    1.57  Insert the specified byte(s) into the code.  Note, unlike BBC BASIC, that a
    1.58 @@ -369,6 +388,39 @@
    1.59              IF debugraster:LDA #3:STA &FE21:ENDIF
    1.60  
    1.61  
    1.62 +{ ... }
    1.63 +
    1.64 +Curly braces can be used to specify a block of code in which all symbols and
    1.65 +labels defined will exist only within this block.  Effectively, this is a
    1.66 +mechanism for providing 'local labels' without the slightly cumbersome syntax
    1.67 +demanded by some other assemblers.  These can be nested.  Any symbols defined
    1.68 +within a block will override any of the same name outside of the block, exactly
    1.69 +like C/C++ - not sure if I like this behaviour, but for now it will stay.
    1.70 +
    1.71 +Example of use:
    1.72 +
    1.73 +    .initialise
    1.74 +    {
    1.75 +        LDY #31
    1.76 +        LDA #0
    1.77 +    .loop                ; label visible only within the braces
    1.78 +        STA buffer,Y
    1.79 +        DEY
    1.80 +        BPL loop
    1.81 +        RTS
    1.82 +    }
    1.83 +
    1.84 +    .copy
    1.85 +    {
    1.86 +        LDY #31
    1.87 +    .loop                ; perfectly ok to define .loop again in a new block
    1.88 +        LDA source,Y
    1.89 +        STA dest,Y
    1.90 +        DEY
    1.91 +        BPL loop
    1.92 +        RTS
    1.93 +    }
    1.94 +
    1.95  
    1.96  
    1.97  7. TIPS AND TRICKS
    1.98 @@ -471,6 +523,11 @@
    1.99  
   1.100  9. VERSION HISTORY
   1.101  
   1.102 +06/01/2008  0.04  Added braces for scoping labels.  Added INCBIN, SKIPTO.
   1.103 +                  Added some missing functions (NOT, LOG, LN, EXP).
   1.104 +                  Tightened up error checking on assembling out of range
   1.105 +                  addresses (negative, or greater than &FFFF).
   1.106 +05/01/2008  0.03  Added symbol dump for use with Swift.
   1.107  20/12/2007  0.02  Fixed small bug which withheld filename and line number
   1.108                    display in error messages.
   1.109  16/12/2007  0.01  First released version.
     2.1 Binary file beebasm.exe has changed
     3.1 --- a/demo.asm	Sun May 02 11:57:59 2010 +0100
     3.2 +++ b/demo.asm	Sun May 02 12:04:21 2010 +0100
     3.3 @@ -54,7 +54,6 @@
     3.4  
     3.5  ORG &1100
     3.6  
     3.7 -
     3.8  \ ******************************************************************
     3.9  \ *	The entry point of the demo
    3.10  \ ******************************************************************
    3.11 @@ -476,3 +475,4 @@
    3.12  \ ******************************************************************
    3.13  
    3.14  SAVE "Code", start, end
    3.15 +
     4.1 Binary file demo.ssd has changed
     5.1 --- a/src/Makefile	Sun May 02 11:57:59 2010 +0100
     5.2 +++ b/src/Makefile	Sun May 02 12:04:21 2010 +0100
     5.3 @@ -35,7 +35,7 @@
     5.4  
     5.5  # Parameters to the executable
     5.6  
     5.7 -PARAMS			:=		-i ..\demo.asm -do ..\demo.ssd -boot Code
     5.8 +PARAMS			:=		-i ..\demo.asm -do ..\demo.ssd -boot Code -d
     5.9  
    5.10  
    5.11  
     6.1 --- a/src/Makefile.inc	Sun May 02 11:57:59 2010 +0100
     6.2 +++ b/src/Makefile.inc	Sun May 02 12:04:21 2010 +0100
     6.3 @@ -21,7 +21,7 @@
     6.4  #		CPUS			The number of CPUs on this machine
     6.5  #		VERBOSE			Echoes all commands launched by make
     6.6  #
     6.7 -#	@author camrtw
     6.8 +#	@author RTW
     6.9  #
    6.10  #**************************************************************************************************
    6.11  
    6.12 @@ -57,9 +57,9 @@
    6.13  CC				:=		C:/MinGW/bin/gcc
    6.14  CXX				:=		C:/MinGW/bin/gcc
    6.15  LD				:=		C:/MinGW/bin/gcc
    6.16 -MKDIR			:=		C:/Cygwin/bin/mkdir -p
    6.17 -RM				:=		C:/Cygwin/bin/rm -f
    6.18 -ECHO			:=		@@C:/Cygwin/bin/echo -e
    6.19 +MKDIR			:=		C:/Utilities/mkdir -p
    6.20 +RM				:=		C:/Utilities/rm -f
    6.21 +ECHO			:=		@@C:/Utilities/echo -e
    6.22  
    6.23  
    6.24  # Declare default number of CPUs
     7.1 --- a/src/asmexception.h	Sun May 02 11:57:59 2010 +0100
     7.2 +++ b/src/asmexception.h	Sun May 02 12:04:21 2010 +0100
     7.3 @@ -175,6 +175,7 @@
     7.4  DEFINE_SYNTAX_EXCEPTION( BranchOutOfRange, "Branch out of range." );
     7.5  DEFINE_SYNTAX_EXCEPTION( NoAbsolute, "Absolute addressing mode not allowed for this instruction." );
     7.6  DEFINE_SYNTAX_EXCEPTION( BadAbsolute, "Syntax error in absolute instruction." );
     7.7 +DEFINE_SYNTAX_EXCEPTION( BadAddress, "Out of range address." );
     7.8  DEFINE_SYNTAX_EXCEPTION( BadIndexed, "Syntax error in indexed instruction." );
     7.9  DEFINE_SYNTAX_EXCEPTION( NoIndexedX, "X indexed mode does not exist for this instruction." );
    7.10  DEFINE_SYNTAX_EXCEPTION( NoIndexedY, "Y indexed mode does not exist for this instruction." );
    7.11 @@ -186,14 +187,16 @@
    7.12  DEFINE_SYNTAX_EXCEPTION( NextWithoutFor, "NEXT without FOR." );
    7.13  DEFINE_SYNTAX_EXCEPTION( ForWithoutNext, "FOR without NEXT." );
    7.14  DEFINE_SYNTAX_EXCEPTION( BadStep, "Step value cannot be zero." );
    7.15 -DEFINE_SYNTAX_EXCEPTION( TooManyFORs, "Too many nested FORs." );
    7.16 -DEFINE_SYNTAX_EXCEPTION( CantInclude, "Cannot include a source file within a FOR loop." );
    7.17 +DEFINE_SYNTAX_EXCEPTION( TooManyFORs, "Too many nested FORs or braces." );
    7.18 +DEFINE_SYNTAX_EXCEPTION( MismatchedBraces, "Mismatched braces." );
    7.19 +DEFINE_SYNTAX_EXCEPTION( CantInclude, "Cannot include a source file within a FOR loop or braced block." );
    7.20  DEFINE_SYNTAX_EXCEPTION( ElseWithoutIf, "ELSE without IF." );
    7.21  DEFINE_SYNTAX_EXCEPTION( EndifWithoutIf, "ENDIF without IF." );
    7.22  DEFINE_SYNTAX_EXCEPTION( IfWithoutEndif, "IF without ENDIF." );
    7.23  DEFINE_SYNTAX_EXCEPTION( TooManyIFs, "Too many nested IFs." );
    7.24  DEFINE_SYNTAX_EXCEPTION( BadAlignment, "Bad alignment." );
    7.25  DEFINE_SYNTAX_EXCEPTION( OutOfRange, "Out of range." );
    7.26 +DEFINE_SYNTAX_EXCEPTION( BackwardsSkip, "Attempted to skip backwards to an address." );
    7.27  
    7.28  
    7.29  
    7.30 @@ -236,6 +239,7 @@
    7.31  DEFINE_ASSEMBLE_EXCEPTION( GuardHit, "Guard point hit." );
    7.32  DEFINE_ASSEMBLE_EXCEPTION( Overlap, "Trying to assemble over existing code." );
    7.33  DEFINE_ASSEMBLE_EXCEPTION( InconsistentCode, "Assembled object code has changed between 1st and 2nd pass. Has a zero-page symbol been forward-declared?" );
    7.34 -
    7.35 +DEFINE_ASSEMBLE_EXCEPTION( FileOpen, "Error opening file." );
    7.36 +DEFINE_ASSEMBLE_EXCEPTION( FileRead, "Error reading file." );
    7.37  
    7.38  #endif // ASMEXCEPTION_H_
     8.1 --- a/src/assemble.cpp	Sun May 02 11:57:59 2010 +0100
     8.2 +++ b/src/assemble.cpp	Sun May 02 12:04:21 2010 +0100
     8.3 @@ -528,6 +528,11 @@
     8.4  					throw AsmException_SyntaxError_NotZeroPage( m_line, oldColumn + 1 );
     8.5  				}
     8.6  
     8.7 +				if ( value < 0 )
     8.8 +				{
     8.9 +					throw AsmException_SyntaxError_BadAddress( m_line, oldColumn + 1 );
    8.10 +				}
    8.11 +
    8.12  				Assemble2( instruction, INDY, value );
    8.13  				return;
    8.14  			}
    8.15 @@ -594,6 +599,11 @@
    8.16  				throw AsmException_SyntaxError_NotZeroPage( m_line, oldColumn + 1 );
    8.17  			}
    8.18  
    8.19 +			if ( value < 0 )
    8.20 +			{
    8.21 +				throw AsmException_SyntaxError_BadAddress( m_line, oldColumn + 1 );
    8.22 +			}
    8.23 +
    8.24  			Assemble2( instruction, INDX, value );
    8.25  			return;
    8.26  		}
    8.27 @@ -656,6 +666,11 @@
    8.28  		// we assemble abs or zp depending on whether 'value' is a 16- or 8-bit number.
    8.29  		// we contrive that unknown labels will get a 16-bit value so that absolute addressing is the default.
    8.30  
    8.31 +		if ( value < 0 || value > 0xFFFF )
    8.32 +		{
    8.33 +			throw AsmException_SyntaxError_BadAddress( m_line, oldColumn );
    8.34 +		}
    8.35 +
    8.36  		if ( value < 0x100 && HasAddressingMode( instruction, ZP ) )
    8.37  		{
    8.38  			Assemble2( instruction, ZP, value );
    8.39 @@ -698,6 +713,11 @@
    8.40  			throw AsmException_SyntaxError_BadIndexed( m_line, m_column );
    8.41  		}
    8.42  
    8.43 +		if ( value < 0 || value > 0xFFFF )
    8.44 +		{
    8.45 +			throw AsmException_SyntaxError_BadAddress( m_line, oldColumn );
    8.46 +		}
    8.47 +
    8.48  		if ( value < 0x100 && HasAddressingMode( instruction, ZPX ) )
    8.49  		{
    8.50  			Assemble2( instruction, ZPX, value );
    8.51 @@ -724,6 +744,11 @@
    8.52  			throw AsmException_SyntaxError_BadIndexed( m_line, m_column );
    8.53  		}
    8.54  
    8.55 +		if ( value < 0 || value > 0xFFFF )
    8.56 +		{
    8.57 +			throw AsmException_SyntaxError_BadAddress( m_line, oldColumn );
    8.58 +		}
    8.59 +
    8.60  		if ( value < 0x100 && HasAddressingMode( instruction, ZPY ) )
    8.61  		{
    8.62  			Assemble2( instruction, ZPY, value );
     9.1 --- a/src/commands.cpp	Sun May 02 11:57:59 2010 +0100
     9.2 +++ b/src/commands.cpp	Sun May 02 12:04:21 2010 +0100
     9.3 @@ -43,7 +43,11 @@
     9.4  	{ "ALIGN",		&LineParser::HandleAlign },
     9.5  	{ "SKIP",		&LineParser::HandleSkip },
     9.6  	{ "GUARD",		&LineParser::HandleGuard },
     9.7 -	{ "CLEAR",		&LineParser::HandleClear }
     9.8 +	{ "CLEAR",		&LineParser::HandleClear },
     9.9 +	{ "SKIPTO",		&LineParser::HandleSkipTo },
    9.10 +	{ "INCBIN",		&LineParser::HandleIncBin },
    9.11 +	{ "{",			&LineParser::HandleOpenBrace },
    9.12 +	{ "}",			&LineParser::HandleCloseBrace }
    9.13  };
    9.14  
    9.15  
    9.16 @@ -125,7 +129,7 @@
    9.17  			}
    9.18  			else
    9.19  			{
    9.20 -				SymbolTable::Instance().AddSymbol( fullSymbolName, ObjectCode::Instance().GetPC() );
    9.21 +				SymbolTable::Instance().AddSymbol( fullSymbolName, ObjectCode::Instance().GetPC(), true );
    9.22  			}
    9.23  		}
    9.24  		else
    9.25 @@ -341,6 +345,49 @@
    9.26  
    9.27  /*************************************************************************************************/
    9.28  /**
    9.29 +	LineParser::HandleSkipTo()
    9.30 +*/
    9.31 +/*************************************************************************************************/
    9.32 +void LineParser::HandleSkipTo()
    9.33 +{
    9.34 +	int oldColumn = m_column;
    9.35 +
    9.36 +	int addr = EvaluateExpressionAsInt();
    9.37 +	if ( addr < 0 || addr > 0xFFFF )
    9.38 +	{
    9.39 +		throw AsmException_SyntaxError_BadAddress( m_line, oldColumn );
    9.40 +	}
    9.41 +
    9.42 +	if ( ObjectCode::Instance().GetPC() > addr )
    9.43 +	{
    9.44 +		throw AsmException_SyntaxError_BackwardsSkip( m_line, oldColumn );
    9.45 +	}
    9.46 +
    9.47 +	while ( ObjectCode::Instance().GetPC() < addr )
    9.48 +	{
    9.49 +		try
    9.50 +		{
    9.51 +			ObjectCode::Instance().PutByte( 0 );
    9.52 +		}
    9.53 +		catch ( AsmException_AssembleError& e )
    9.54 +		{
    9.55 +			e.SetString( m_line );
    9.56 +			e.SetColumn( m_column );
    9.57 +			throw;
    9.58 +		}
    9.59 +	}
    9.60 +
    9.61 +	if ( m_line[ m_column ] == ',' )
    9.62 +	{
    9.63 +		// Unexpected comma (remembering that an expression can validly end with a comma)
    9.64 +		throw AsmException_SyntaxError_UnexpectedComma( m_line, m_column );
    9.65 +	}
    9.66 +}
    9.67 +
    9.68 +
    9.69 +
    9.70 +/*************************************************************************************************/
    9.71 +/**
    9.72  	LineParser::HandleInclude()
    9.73  */
    9.74  /*************************************************************************************************/
    9.75 @@ -375,7 +422,7 @@
    9.76  
    9.77  		if ( GlobalData::Instance().IsFirstPass() )
    9.78  		{
    9.79 -			cout << "Including file " << filename << endl;
    9.80 +			cerr << "Including file " << filename << endl;
    9.81  		}
    9.82  
    9.83  		SourceFile input( filename.c_str() );
    9.84 @@ -394,6 +441,56 @@
    9.85  
    9.86  /*************************************************************************************************/
    9.87  /**
    9.88 +	LineParser::HandleIncBin()
    9.89 +*/
    9.90 +/*************************************************************************************************/
    9.91 +void LineParser::HandleIncBin()
    9.92 +{
    9.93 +	if ( !AdvanceAndCheckEndOfStatement() )
    9.94 +	{
    9.95 +		throw AsmException_SyntaxError_EmptyExpression( m_line, m_column );
    9.96 +	}
    9.97 +
    9.98 +	if ( m_line[ m_column ] != '\"' )
    9.99 +	{
   9.100 +		throw AsmException_SyntaxError_EmptyExpression( m_line, m_column );
   9.101 +	}
   9.102 +
   9.103 +	// string
   9.104 +	size_t endQuotePos = m_line.find_first_of( '\"', m_column + 1 );
   9.105 +
   9.106 +	if ( endQuotePos == string::npos )
   9.107 +	{
   9.108 +		throw AsmException_SyntaxError_MissingQuote( m_line, m_line.length() );
   9.109 +	}
   9.110 +	else
   9.111 +	{
   9.112 +		string filename( m_line.substr( m_column + 1, endQuotePos - m_column - 1 ) );
   9.113 +
   9.114 +		try
   9.115 +		{
   9.116 +			ObjectCode::Instance().IncBin( filename.c_str() );
   9.117 +		}
   9.118 +		catch ( AsmException_AssembleError& e )
   9.119 +		{
   9.120 +			e.SetString( m_line );
   9.121 +			e.SetColumn( m_column );
   9.122 +			throw;
   9.123 +		}
   9.124 +	}
   9.125 +
   9.126 +	m_column = endQuotePos + 1;
   9.127 +
   9.128 +	if ( AdvanceAndCheckEndOfStatement() )
   9.129 +	{
   9.130 +		throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column );
   9.131 +	}
   9.132 +}
   9.133 +
   9.134 +
   9.135 +
   9.136 +/*************************************************************************************************/
   9.137 +/**
   9.138  	LineParser::HandleEqub()
   9.139  */
   9.140  /*************************************************************************************************/
   9.141 @@ -868,6 +965,18 @@
   9.142  
   9.143  /*************************************************************************************************/
   9.144  /**
   9.145 +	LineParser::HandleOpenBrace()
   9.146 +*/
   9.147 +/*************************************************************************************************/
   9.148 +void LineParser::HandleOpenBrace()
   9.149 +{
   9.150 +	m_sourceFile->OpenBrace( m_line, m_column - 1 );
   9.151 +}
   9.152 +
   9.153 +
   9.154 +
   9.155 +/*************************************************************************************************/
   9.156 +/**
   9.157  	LineParser::HandleNext()
   9.158  */
   9.159  /*************************************************************************************************/
   9.160 @@ -888,6 +997,20 @@
   9.161  
   9.162  /*************************************************************************************************/
   9.163  /**
   9.164 +	LineParser::HandleCloseBrace()
   9.165 +
   9.166 +	Braces for scoping variables are just FORs in disguise...
   9.167 +*/
   9.168 +/*************************************************************************************************/
   9.169 +void LineParser::HandleCloseBrace()
   9.170 +{
   9.171 +	m_sourceFile->CloseBrace( m_line, m_column - 1 );
   9.172 +}
   9.173 +
   9.174 +
   9.175 +
   9.176 +/*************************************************************************************************/
   9.177 +/**
   9.178  	LineParser::HandleIf()
   9.179  */
   9.180  /*************************************************************************************************/
    10.1 --- a/src/expression.cpp	Sun May 02 11:57:59 2010 +0100
    10.2 +++ b/src/expression.cpp	Sun May 02 12:04:21 2010 +0100
    10.3 @@ -75,7 +75,11 @@
    10.4  	{ "INT",	10,	&LineParser::EvalInt },
    10.5  	{ "ABS",	10, &LineParser::EvalAbs },
    10.6  	{ "SGN",	10, &LineParser::EvalSgn },
    10.7 -	{ "RND",	10,	&LineParser::EvalRnd }
    10.8 +	{ "RND",	10,	&LineParser::EvalRnd },
    10.9 +	{ "NOT",	10, &LineParser::EvalNot },
   10.10 +	{ "LOG",	10, &LineParser::EvalLog },
   10.11 +	{ "LN",		10,	&LineParser::EvalLn },
   10.12 +	{ "EXP",	10,	&LineParser::EvalExp }
   10.13  };
   10.14  
   10.15  
   10.16 @@ -841,6 +845,23 @@
   10.17  
   10.18  /*************************************************************************************************/
   10.19  /**
   10.20 +	LineParser::EvalNot()
   10.21 +*/
   10.22 +/*************************************************************************************************/
   10.23 +void LineParser::EvalNot()
   10.24 +{
   10.25 +	if ( m_valueStackPtr < 1 )
   10.26 +	{
   10.27 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
   10.28 +	}
   10.29 +	m_valueStack[ m_valueStackPtr - 1 ] = static_cast< double >(
   10.30 +		~static_cast< int >( m_valueStack[ m_valueStackPtr - 1 ] ) );
   10.31 +}
   10.32 +
   10.33 +
   10.34 +
   10.35 +/*************************************************************************************************/
   10.36 +/**
   10.37  	LineParser::EvalPosate()
   10.38  */
   10.39  /*************************************************************************************************/
   10.40 @@ -1002,6 +1023,69 @@
   10.41  
   10.42  /*************************************************************************************************/
   10.43  /**
   10.44 +	LineParser::EvalLog()
   10.45 +*/
   10.46 +/*************************************************************************************************/
   10.47 +void LineParser::EvalLog()
   10.48 +{
   10.49 +	if ( m_valueStackPtr < 1 )
   10.50 +	{
   10.51 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
   10.52 +	}
   10.53 +	m_valueStack[ m_valueStackPtr - 1 ] = log10( m_valueStack[ m_valueStackPtr - 1 ] );
   10.54 +
   10.55 +	if ( errno == EDOM || errno == ERANGE )
   10.56 +	{
   10.57 +		throw AsmException_SyntaxError_IllegalOperation( m_line, m_column - 1 );
   10.58 +	}
   10.59 +}
   10.60 +
   10.61 +
   10.62 +
   10.63 +/*************************************************************************************************/
   10.64 +/**
   10.65 +	LineParser::EvalLn()
   10.66 +*/
   10.67 +/*************************************************************************************************/
   10.68 +void LineParser::EvalLn()
   10.69 +{
   10.70 +	if ( m_valueStackPtr < 1 )
   10.71 +	{
   10.72 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
   10.73 +	}
   10.74 +	m_valueStack[ m_valueStackPtr - 1 ] = log( m_valueStack[ m_valueStackPtr - 1 ] );
   10.75 +
   10.76 +	if ( errno == EDOM || errno == ERANGE )
   10.77 +	{
   10.78 +		throw AsmException_SyntaxError_IllegalOperation( m_line, m_column - 1 );
   10.79 +	}
   10.80 +}
   10.81 +
   10.82 +
   10.83 +
   10.84 +/*************************************************************************************************/
   10.85 +/**
   10.86 +	LineParser::EvalExp()
   10.87 +*/
   10.88 +/*************************************************************************************************/
   10.89 +void LineParser::EvalExp()
   10.90 +{
   10.91 +	if ( m_valueStackPtr < 1 )
   10.92 +	{
   10.93 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
   10.94 +	}
   10.95 +	m_valueStack[ m_valueStackPtr - 1 ] = exp( m_valueStack[ m_valueStackPtr - 1 ] );
   10.96 +
   10.97 +	if ( errno == ERANGE )
   10.98 +	{
   10.99 +		throw AsmException_SyntaxError_IllegalOperation( m_line, m_column - 1 );
  10.100 +	}
  10.101 +}
  10.102 +
  10.103 +
  10.104 +
  10.105 +/*************************************************************************************************/
  10.106 +/**
  10.107  	LineParser::EvalSqrt()
  10.108  */
  10.109  /*************************************************************************************************/
    11.1 --- a/src/lineparser.h	Sun May 02 11:57:59 2010 +0100
    11.2 +++ b/src/lineparser.h	Sun May 02 12:04:21 2010 +0100
    11.3 @@ -108,16 +108,20 @@
    11.4  	void			HandlePrint();
    11.5  	void			HandleOrg();
    11.6  	void			HandleInclude();
    11.7 +	void			HandleIncBin();
    11.8  	void			HandleEqub();
    11.9  	void			HandleEquw();
   11.10  	void			HandleSave();
   11.11  	void			HandleFor();
   11.12  	void			HandleNext();
   11.13 +	void			HandleOpenBrace();
   11.14 +	void			HandleCloseBrace();
   11.15  	void			HandleIf();
   11.16  	void			HandleElse();
   11.17  	void			HandleEndif();
   11.18  	void			HandleAlign();
   11.19  	void			HandleSkip();
   11.20 +	void			HandleSkipTo();
   11.21  	void			HandleGuard();
   11.22  	void			HandleClear();
   11.23  
   11.24 @@ -163,6 +167,10 @@
   11.25  	void			EvalAbs();
   11.26  	void			EvalSgn();
   11.27  	void			EvalRnd();
   11.28 +	void			EvalNot();
   11.29 +	void			EvalLog();
   11.30 +	void			EvalLn();
   11.31 +	void			EvalExp();
   11.32  
   11.33  
   11.34  	SourceFile*				m_sourceFile;
    12.1 --- a/src/main.cpp	Sun May 02 11:57:59 2010 +0100
    12.2 +++ b/src/main.cpp	Sun May 02 12:04:21 2010 +0100
    12.3 @@ -23,7 +23,7 @@
    12.4  using namespace std;
    12.5  
    12.6  
    12.7 -#define VERSION "0.02"
    12.8 +#define VERSION "0.03"
    12.9  
   12.10  
   12.11  /*************************************************************************************************/
   12.12 @@ -53,6 +53,7 @@
   12.13  
   12.14  	} state = READY;
   12.15  
   12.16 +	bool bDumpSymbols = false;
   12.17  
   12.18  	GlobalData::Create();
   12.19  
   12.20 @@ -84,6 +85,10 @@
   12.21  				{
   12.22  					GlobalData::Instance().SetVerbose( true );
   12.23  				}
   12.24 +				else if ( strcmp( argv[i], "-d" ) == 0 )
   12.25 +				{
   12.26 +					bDumpSymbols = true;
   12.27 +				}
   12.28  				else if ( strcmp( argv[i], "--help" ) == 0 )
   12.29  				{
   12.30  					cout << "beebasm " VERSION << endl << endl;
   12.31 @@ -93,6 +98,7 @@
   12.32  					cout << " -do <file>     Specify a disc image file to output" << endl;
   12.33  					cout << " -boot <file>   Specify a filename to be run by !BOOT on a new disc image" << endl;
   12.34  					cout << " -v             Verbose output" << endl;
   12.35 +					cout << " -d             Dump all global symbols after assembly" << endl;
   12.36  					cout << " --help         See this help again" << endl;
   12.37  					return EXIT_SUCCESS;
   12.38  				}
   12.39 @@ -196,6 +202,11 @@
   12.40  
   12.41  	delete pDiscIm;
   12.42  
   12.43 +	if ( bDumpSymbols && exitCode == EXIT_SUCCESS )
   12.44 +	{
   12.45 +		SymbolTable::Instance().Dump();
   12.46 +	}
   12.47 +
   12.48  	ObjectCode::Destroy();
   12.49  	SymbolTable::Destroy();
   12.50  	GlobalData::Destroy();
    13.1 --- a/src/objectcode.cpp	Sun May 02 11:57:59 2010 +0100
    13.2 +++ b/src/objectcode.cpp	Sun May 02 12:04:21 2010 +0100
    13.3 @@ -6,6 +6,7 @@
    13.4  
    13.5  #include <cstring>
    13.6  #include <iostream>
    13.7 +#include <fstream>
    13.8  
    13.9  #include "objectcode.h"
   13.10  #include "symboltable.h"
   13.11 @@ -283,3 +284,37 @@
   13.12  	}
   13.13  	memset( m_aFlags + start, 0, end - start );
   13.14  }
   13.15 +
   13.16 +
   13.17 +
   13.18 +/*************************************************************************************************/
   13.19 +/**
   13.20 +	ObjectCode::IncBin()
   13.21 +*/
   13.22 +/*************************************************************************************************/
   13.23 +void ObjectCode::IncBin( const char* filename )
   13.24 +{
   13.25 +	ifstream binfile;
   13.26 +
   13.27 +	binfile.open( filename, ios_base::in | ios_base::binary );
   13.28 +
   13.29 +	if ( !binfile )
   13.30 +	{
   13.31 +		throw AsmException_AssembleError_FileOpen();
   13.32 +	}
   13.33 +
   13.34 +	char c;
   13.35 +
   13.36 +	while ( binfile.get( c ) )
   13.37 +	{
   13.38 +		assert( binfile.gcount() == 1 );
   13.39 +		Assemble1( static_cast< unsigned char >( c ) );
   13.40 +	}
   13.41 +
   13.42 +	if ( !binfile.eof() )
   13.43 +	{
   13.44 +		throw AsmException_AssembleError_FileRead();
   13.45 +	}
   13.46 +
   13.47 +	binfile.close();
   13.48 +}
    14.1 --- a/src/objectcode.h	Sun May 02 11:57:59 2010 +0100
    14.2 +++ b/src/objectcode.h	Sun May 02 12:04:21 2010 +0100
    14.3 @@ -28,6 +28,7 @@
    14.4  	void Assemble1( unsigned int opcode );
    14.5  	void Assemble2( unsigned int opcode, unsigned int val );
    14.6  	void Assemble3( unsigned int opcode, unsigned int addr );
    14.7 +	void IncBin( const char* filename );
    14.8  
    14.9  	void SetGuard( int i );
   14.10  	void Clear( int start, int end, bool bAll = true );
    15.1 --- a/src/sourcefile.cpp	Sun May 02 11:57:59 2010 +0100
    15.2 +++ b/src/sourcefile.cpp	Sun May 02 12:04:21 2010 +0100
    15.3 @@ -125,16 +125,26 @@
    15.4  		throw AsmException_FileError_ReadSourceFile( m_pFilename );
    15.5  	}
    15.6  
    15.7 -	// Check that we have no FOR mismatch
    15.8 +	// Check that we have no FOR / braces mismatch
    15.9  
   15.10  	if ( m_forStackPtr > 0 )
   15.11  	{
   15.12  		For& mismatchedFor = m_forStack[ m_forStackPtr - 1 ];
   15.13  
   15.14 -		AsmException_SyntaxError_ForWithoutNext e( mismatchedFor.m_line, mismatchedFor.m_column );
   15.15 -		e.SetFilename( m_pFilename );
   15.16 -		e.SetLineNumber( mismatchedFor.m_lineNumber );
   15.17 -		throw e;
   15.18 +		if ( mismatchedFor.m_step == 0.0 )
   15.19 +		{
   15.20 +			AsmException_SyntaxError_MismatchedBraces e( mismatchedFor.m_line, mismatchedFor.m_column );
   15.21 +			e.SetFilename( m_pFilename );
   15.22 +			e.SetLineNumber( mismatchedFor.m_lineNumber );
   15.23 +			throw e;
   15.24 +		}
   15.25 +		else
   15.26 +		{
   15.27 +			AsmException_SyntaxError_ForWithoutNext e( mismatchedFor.m_line, mismatchedFor.m_column );
   15.28 +			e.SetFilename( m_pFilename );
   15.29 +			e.SetLineNumber( mismatchedFor.m_lineNumber );
   15.30 +			throw e;
   15.31 +		}
   15.32  	}
   15.33  
   15.34  	// Check that we have no IF mismatch
   15.35 @@ -153,7 +163,7 @@
   15.36  
   15.37  	if ( GlobalData::Instance().IsFirstPass() )
   15.38  	{
   15.39 -		cout << "Processed file '" << m_pFilename << "' ok" << endl << endl;
   15.40 +		cerr << "Processed file '" << m_pFilename << "' ok" << endl << endl;
   15.41  	}
   15.42  }
   15.43  
   15.44 @@ -201,6 +211,38 @@
   15.45  
   15.46  /*************************************************************************************************/
   15.47  /**
   15.48 +	SourceFile::OpenBrace()
   15.49 +
   15.50 +	Braces for scoping variables are just FORs in disguise...
   15.51 +*/
   15.52 +/*************************************************************************************************/
   15.53 +void SourceFile::OpenBrace( string line, int column )
   15.54 +{
   15.55 +	if ( m_forStackPtr == MAX_FOR_LEVELS )
   15.56 +	{
   15.57 +		throw AsmException_SyntaxError_TooManyFORs( line, column );
   15.58 +	}
   15.59 +
   15.60 +	// Fill in FOR block
   15.61 +
   15.62 +	m_forStack[ m_forStackPtr ].m_varName		= "";
   15.63 +	m_forStack[ m_forStackPtr ].m_current		= 1.0;
   15.64 +	m_forStack[ m_forStackPtr ].m_end			= 0.0;
   15.65 +	m_forStack[ m_forStackPtr ].m_step			= 0.0;
   15.66 +	m_forStack[ m_forStackPtr ].m_filePtr		= 0;
   15.67 +	m_forStack[ m_forStackPtr ].m_id			= GlobalData::Instance().GetNextForId();
   15.68 +	m_forStack[ m_forStackPtr ].m_count			= 0;
   15.69 +	m_forStack[ m_forStackPtr ].m_line			= line;
   15.70 +	m_forStack[ m_forStackPtr ].m_column		= column;
   15.71 +	m_forStack[ m_forStackPtr ].m_lineNumber	= m_lineNumber;
   15.72 +
   15.73 +	m_forStackPtr++;
   15.74 +}
   15.75 +
   15.76 +
   15.77 +
   15.78 +/*************************************************************************************************/
   15.79 +/**
   15.80  	SourceFile::UpdateFor()
   15.81  */
   15.82  /*************************************************************************************************/
   15.83 @@ -213,6 +255,13 @@
   15.84  
   15.85  	For& thisFor = m_forStack[ m_forStackPtr - 1 ];
   15.86  
   15.87 +	// step of 0.0 here means that the 'for' is in fact an open brace, so throw an error
   15.88 +
   15.89 +	if ( thisFor.m_step == 0.0 )
   15.90 +	{
   15.91 +		throw AsmException_SyntaxError_NextWithoutFor( line, column );
   15.92 +	}
   15.93 +
   15.94  	thisFor.m_current += thisFor.m_step;
   15.95  
   15.96  	if ( ( thisFor.m_step > 0.0 && thisFor.m_current > thisFor.m_end ) ||
   15.97 @@ -236,6 +285,34 @@
   15.98  
   15.99  /*************************************************************************************************/
  15.100  /**
  15.101 +	SourceFile::CloseBrace()
  15.102 +
  15.103 +	Braces for scoping variables are just FORs in disguise...
  15.104 +*/
  15.105 +/*************************************************************************************************/
  15.106 +void SourceFile::CloseBrace( string line, int column )
  15.107 +{
  15.108 +	if ( m_forStackPtr == 0 )
  15.109 +	{
  15.110 +		throw AsmException_SyntaxError_MismatchedBraces( line, column );
  15.111 +	}
  15.112 +
  15.113 +	For& thisFor = m_forStack[ m_forStackPtr - 1 ];
  15.114 +
  15.115 +	// step of non-0.0 here means that this a real 'for', so throw an error
  15.116 +
  15.117 +	if ( thisFor.m_step != 0.0 )
  15.118 +	{
  15.119 +		throw AsmException_SyntaxError_MismatchedBraces( line, column );
  15.120 +	}
  15.121 +
  15.122 +	m_forStackPtr--;
  15.123 +}
  15.124 +
  15.125 +
  15.126 +
  15.127 +/*************************************************************************************************/
  15.128 +/**
  15.129  	SourceFile::GetSymbolNameSuffix()
  15.130  */
  15.131  /*************************************************************************************************/
    16.1 --- a/src/sourcefile.h	Sun May 02 11:57:59 2010 +0100
    16.2 +++ b/src/sourcefile.h	Sun May 02 12:04:21 2010 +0100
    16.3 @@ -34,8 +34,8 @@
    16.4  
    16.5  	// For loop / if related stuff
    16.6  
    16.7 -	#define MAX_FOR_LEVELS	16
    16.8 -	#define MAX_IF_LEVELS	16
    16.9 +	#define MAX_FOR_LEVELS	32
   16.10 +	#define MAX_IF_LEVELS	32
   16.11  
   16.12  private:
   16.13  
   16.14 @@ -69,6 +69,9 @@
   16.15  
   16.16  public:
   16.17  
   16.18 +	void					OpenBrace( std::string line, int column );
   16.19 +	void					CloseBrace( std::string line, int column );
   16.20 +
   16.21  	void					AddFor( std::string varName,
   16.22  									double start,
   16.23  									double end,
    17.1 --- a/src/symboltable.cpp	Sun May 02 11:57:59 2010 +0100
    17.2 +++ b/src/symboltable.cpp	Sun May 02 12:04:21 2010 +0100
    17.3 @@ -5,12 +5,17 @@
    17.4  /*************************************************************************************************/
    17.5  
    17.6  #include <cmath>
    17.7 +#include <iostream>
    17.8 +
    17.9  #include "symboltable.h"
   17.10  
   17.11 +
   17.12 +using namespace std;
   17.13 +
   17.14 +
   17.15  SymbolTable* SymbolTable::m_gInstance = NULL;
   17.16  
   17.17  
   17.18 -
   17.19  /*************************************************************************************************/
   17.20  /**
   17.21  	SymbolTable::Create()
   17.22 @@ -103,10 +108,10 @@
   17.23  	@param		int				Its value
   17.24  */
   17.25  /*************************************************************************************************/
   17.26 -void SymbolTable::AddSymbol( const std::string& symbol, double value )
   17.27 +void SymbolTable::AddSymbol( const std::string& symbol, double value, bool isLabel )
   17.28  {
   17.29  	assert( !IsSymbolDefined( symbol ) );
   17.30 -	m_map.insert( make_pair( symbol, value ) );
   17.31 +	m_map.insert( make_pair( symbol, Symbol( value, isLabel ) ) );
   17.32  }
   17.33  
   17.34  
   17.35 @@ -123,7 +128,7 @@
   17.36  double SymbolTable::GetSymbol( const std::string& symbol ) const
   17.37  {
   17.38  	assert( IsSymbolDefined( symbol ) );
   17.39 -	return m_map.find( symbol )->second;
   17.40 +	return m_map.find( symbol )->second.GetValue();
   17.41  }
   17.42  
   17.43  
   17.44 @@ -141,7 +146,7 @@
   17.45  void SymbolTable::ChangeSymbol( const std::string& symbol, double value )
   17.46  {
   17.47  	assert( IsSymbolDefined( symbol ) );
   17.48 -	m_map.find( symbol )->second = value;
   17.49 +	m_map.find( symbol )->second.SetValue( value );
   17.50  }
   17.51  
   17.52  
   17.53 @@ -160,3 +165,40 @@
   17.54  	assert( IsSymbolDefined( symbol ) );
   17.55  	m_map.erase( symbol );
   17.56  }
   17.57 +
   17.58 +
   17.59 +
   17.60 +/*************************************************************************************************/
   17.61 +/**
   17.62 +	SymbolTable::Dump()
   17.63 +
   17.64 +	Dumps all global symbols in the symbol table
   17.65 +*/
   17.66 +/*************************************************************************************************/
   17.67 +void SymbolTable::Dump() const
   17.68 +{
   17.69 +	cout << "[{";
   17.70 +
   17.71 +	bool bFirst = true;
   17.72 +
   17.73 +	for ( map<string, Symbol>::const_iterator it = m_map.begin(); it != m_map.end(); ++it )
   17.74 +	{
   17.75 +		const string&	symbolName = it->first;
   17.76 +		const Symbol&	symbol = it->second;
   17.77 +
   17.78 +		if ( symbol.IsLabel() &&
   17.79 +			 symbolName.find_first_of( '@' ) == string::npos )
   17.80 +		{
   17.81 +			if ( !bFirst )
   17.82 +			{
   17.83 +				cout << ",";
   17.84 +			}
   17.85 +
   17.86 +			cout << "'" << symbolName << "':" << symbol.GetValue() << "L";
   17.87 +
   17.88 +			bFirst = false;
   17.89 +		}
   17.90 +	}
   17.91 +
   17.92 +	cout << "}]" << endl;
   17.93 +}
    18.1 --- a/src/symboltable.h	Sun May 02 11:57:59 2010 +0100
    18.2 +++ b/src/symboltable.h	Sun May 02 12:04:21 2010 +0100
    18.3 @@ -21,19 +21,37 @@
    18.4  	static void Destroy();
    18.5  	static inline SymbolTable& Instance() { assert( m_gInstance != NULL ); return *m_gInstance; }
    18.6  
    18.7 -	void AddSymbol( const std::string& symbol, double value );
    18.8 +	void AddSymbol( const std::string& symbol, double value, bool isLabel = false );
    18.9  	void ChangeSymbol( const std::string& symbol, double value );
   18.10  	double GetSymbol( const std::string& symbol ) const;
   18.11  	bool IsSymbolDefined( const std::string& symbol ) const;
   18.12  	void RemoveSymbol( const std::string& symbol );
   18.13  
   18.14 +	void Dump() const;
   18.15 +
   18.16  
   18.17  private:
   18.18  
   18.19 +	class Symbol
   18.20 +	{
   18.21 +	public:
   18.22 +
   18.23 +		Symbol( double value, bool isLabel ) : m_value( value ), m_isLabel( isLabel ) {}
   18.24 +
   18.25 +		void SetValue( double d ) { m_value = d; }
   18.26 +		double GetValue() const { return m_value; }
   18.27 +		bool IsLabel() const { return m_isLabel; }
   18.28 +
   18.29 +	private:
   18.30 +
   18.31 +		double	m_value;
   18.32 +		bool	m_isLabel;
   18.33 +	};
   18.34 +
   18.35  	SymbolTable();
   18.36  	~SymbolTable();
   18.37  
   18.38 -	std::map<std::string, double>	m_map;
   18.39 +	std::map<std::string, Symbol>	m_map;
   18.40  
   18.41  	static SymbolTable*				m_gInstance;
   18.42  };