beebasm

changeset 0:20042897fa7e

BeebASM v0.01 - first released Dec 20 2007 13:50:25
author Samwise <samwise@bagshot-row.org>
date Sat May 01 19:35:42 2010 +0100
parents
children 9d9b298084e3
files about.txt beebasm.exe demo.asm demo.ssd src/Makefile src/Makefile.inc src/asmexception.cpp src/asmexception.h src/assemble.cpp src/commands.cpp src/discimage.cpp src/discimage.h src/expression.cpp src/globaldata.cpp src/globaldata.h src/lineparser.cpp src/lineparser.h src/main.cpp src/main.h src/objectcode.cpp src/objectcode.h src/sourcefile.cpp src/sourcefile.h src/stringutils.cpp src/stringutils.h src/symboltable.cpp src/symboltable.h src/tokens.h
diffstat 28 files changed, 6754 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/about.txt	Sat May 01 19:35:42 2010 +0100
     1.3 @@ -0,0 +1,485 @@
     1.4 +*******************************************************************************
     1.5 +*                                                                             *
     1.6 +*                                   BeebAsm                                   *
     1.7 +*                                                                             *
     1.8 +*             A portable 6502 assembler with BBC Micro style syntax           *
     1.9 +*                                                                             *
    1.10 +*                   Rich Talbot-Watkins <rich_tw@hotmail.com>                 *
    1.11 +*                                                                             *
    1.12 +*******************************************************************************
    1.13 +
    1.14 +
    1.15 +CONTENTS
    1.16 +
    1.17 + 1. ABOUT BEEBASM
    1.18 + 2. BEEBASM 'PHILOSOPHY'
    1.19 + 3. EXAMPLE
    1.20 + 4. COMMAND LINE OPTIONS
    1.21 + 5. SOURCE FILE SYNTAX
    1.22 + 6. ASSEMBLER DIRECTIVES
    1.23 + 7. TIPS AND TRICKS
    1.24 + 8. DEMO
    1.25 + 9. VERSION HISTORY
    1.26 +10. REPORTING BUGS
    1.27 +
    1.28 +
    1.29 +
    1.30 +1. ABOUT BEEBASM
    1.31 +
    1.32 +BeebAsm is a 6502 assembler designed specially for developing assembler
    1.33 +programs for the BBC Micro.  It uses syntax reminiscent of BBC BASIC's built-in
    1.34 +assembler, and is able to output its object code directly into emulator-ready
    1.35 +DFS disc images.
    1.36 +
    1.37 +Many of the luxuries which come from assembling within the BBC BASIC
    1.38 +environment on a real BBC Micro are also available here, including FOR...NEXT
    1.39 +loops, conditional assembly (IF...ELSE...ENDIF), and all of BASIC's numerical
    1.40 +functions, including SIN, COS and SQR - very useful for building lookup tables
    1.41 +directly within a source file.
    1.42 +
    1.43 +BeebAsm is distributed with source code, and should be easily portable to any
    1.44 +platform you wish.
    1.45 +
    1.46 +
    1.47 +
    1.48 +
    1.49 +2. BEEBASM 'PHILOSOPHY'
    1.50 +
    1.51 +BeebAsm is not like most modern assemblers, in that it doesn't just accept a
    1.52 +source file, and output the corresponding object code file - after all, what
    1.53 +use is a raw 6502 executable file on a PC, outside of an emulated BBC Micro
    1.54 +environment?
    1.55 +
    1.56 +Although BeebAsm *is* able to do this, this isn't the way it was intended to be
    1.57 +used.  Instead, BeebAsm can be pointed at a BBC Micro DFS disc image (.ssd or
    1.58 +.dsd file), and can save blocks of assembled object code directly onto the
    1.59 +'disc', as many or as few as you wish.  It is up to the source code to specify
    1.60 +which blocks of assembled code to save, and with which name, just as if you
    1.61 +were assembling from within BBC BASIC itself.
    1.62 +
    1.63 +
    1.64 +
    1.65 +
    1.66 +3. EXAMPLE
    1.67 +
    1.68 +Rather than trying to explain anything about BeebAsm now, let's leap straight
    1.69 +into an example, as it can probably illustrate more about how BeebAsm should
    1.70 +be used than a thousand lines of text.
    1.71 +
    1.72 +Take the following highly contrived source file: simple.asm
    1.73 +
    1.74 +-------------------------------------------------------------------------------
    1.75 +\ Simple example illustrating use of BeebAsm
    1.76 +
    1.77 +oswrch = &FFEE
    1.78 +osasci = &FFE3
    1.79 +addr = &70
    1.80 +
    1.81 +ORG &2000         ; code origin (like P%=&2000)
    1.82 +
    1.83 +.start
    1.84 +    LDA #22:JSR oswrch
    1.85 +    LDA #7:JSR oswrch
    1.86 +    LDX #mytext MOD 256:STA addr
    1.87 +    LDY #mytext DIV 256:STA addr+1
    1.88 +    LDY #0
    1.89 +.loop
    1.90 +    LDA (addr),Y
    1.91 +    BEQ finished
    1.92 +    JSR osasci
    1.93 +    INY
    1.94 +    BNE loop
    1.95 +.finished
    1.96 +    RTS
    1.97 +
    1.98 +.mytext EQUS "Hello world!", 13, 0
    1.99 +.end
   1.100 +
   1.101 +SAVE "MyCode", start, end
   1.102 +-------------------------------------------------------------------------------
   1.103 +
   1.104 +...and then build it with the following command:
   1.105 +
   1.106 +beebasm -i simple.asm -do test.ssd -boot MyCode -v
   1.107 +
   1.108 +This will do the following:
   1.109 +
   1.110 +* create a new disc image called test.ssd, set to *OPT 4,3
   1.111 +* assemble the 6502 code and create an executable on the disc called 'MyCode'
   1.112 +* create a !Boot file containing '*RUN MyCode'
   1.113 +* output a listing of the assembled code
   1.114 +
   1.115 +Note how the syntax in the source file is very much like BBC BASIC, with a few
   1.116 +small differences which we'll look at in detail later.
   1.117 +
   1.118 +Note also that the source code tells the assembler what should be saved - in
   1.119 +this example, all of the assembled code (from .start to .end), with the
   1.120 +filename 'MyCode'.  This might at first seem strange, but it's actually very
   1.121 +simple and powerful: you have absolute control over what gets saved.  If we
   1.122 +wished, we could assemble more code elsewhere and save it as a separate file,
   1.123 +whilst all the defined labels remained visible to both chunks of code.
   1.124 +
   1.125 +
   1.126 +
   1.127 +
   1.128 +4. COMMAND LINE OPTIONS
   1.129 +
   1.130 +At its very most basic, you need know only one command line option:
   1.131 +
   1.132 +-i <filename>
   1.133 +
   1.134 +This specifies the name of the source file for BeebAsm to process.  In the
   1.135 +absence of any switches specifying disc image filenames, SAVE commands in the
   1.136 +source code will write out object files directly to the current directory.
   1.137 +
   1.138 +-do <filename>
   1.139 +
   1.140 +This specifies the name of a new disc image to be created.  All object code
   1.141 +files will be saved to within this disc image.
   1.142 +
   1.143 +-boot <DFS filename>
   1.144 +
   1.145 +If specifed, BeebAsm will create a !Boot file on the new disc image, containing
   1.146 +the command '*RUN <DFS filename>'.  The new disc image will already be set to
   1.147 +*OPT 4,3 (*EXEC !Boot).
   1.148 +
   1.149 +-di <filename>
   1.150 +
   1.151 +If specified, BeebAsm will use this disc image as a template for the new disc
   1.152 +image, rather than creating a new blank one.  This is useful if you have a
   1.153 +BASIC loader which you want to run before your executable.  Note this cannot be
   1.154 +the same as the -do filename!
   1.155 +
   1.156 +-v
   1.157 +
   1.158 +Verbose output.  Assembled code will be output to the screen.
   1.159 +
   1.160 +
   1.161 +
   1.162 +
   1.163 +5. SOURCE FILE SYNTAX
   1.164 +
   1.165 +Assembler instructions are written with the standard 6502 syntax.
   1.166 +
   1.167 +A label is defined by preceding it with a ".", as per the BBC Micro assembler,
   1.168 +e.g.  .loop
   1.169 +
   1.170 +Instructions can be written one-per-line, or many on one line, separated by
   1.171 +colons.  A label need not be followed by a colon.
   1.172 +
   1.173 +Comments are introduced by a semicolon or backslash.  Unlike the BBC Micro
   1.174 +assembler, these continue to the end of the line, and are not terminated by a
   1.175 +colon (because this BBC Micro feature is horrible!).
   1.176 +
   1.177 +Numeric literals are in decimal by default, and can be integers or reals.
   1.178 +Hex literals are prefixed with "&".
   1.179 +A character in single quotes (e.g. 'A') returns its ASCII code.
   1.180 +
   1.181 +BeebAsm can accept complex expressions, using a wide variety of operators and
   1.182 +functions.  Here's a summary:
   1.183 +
   1.184 ++ - * /            Addition, subtraction, multiplication, division.
   1.185 +<<                 Arithmetic shift left; same precedence as multiplication
   1.186 +>>                 Arithmetic shift right; same precedence as division
   1.187 +^                  Raise to the power of.
   1.188 +() or []           Bracketed expression.  Use [] to avoid confusion with
   1.189 +                   6502 indirect instructions.
   1.190 += or ==            Test equality.  Returns 0 or -1.
   1.191 +<> or !=           Test non-equality.  Returns 0 or -1.
   1.192 +< > <= >=          Other comparisons.  Returns 0 or -1.
   1.193 +AND                Bitwise AND.
   1.194 +OR                 Bitwise OR.
   1.195 +EOR                Bitwise EOR.
   1.196 +DIV                Integer division.
   1.197 +MOD                Integer modulus.
   1.198 +
   1.199 +LO(val) or <val    Return lsb of 16-bit expression (like 'val MOD 256')
   1.200 +HI(val) or >val    Return msb of 16-bit expression (like 'val DIV 256')
   1.201 +-                  Negate (unary minus)
   1.202 +SQR(val)           Return square root of val
   1.203 +SIN(val)           Return sine of val
   1.204 +COS(val)           Return cosine of val
   1.205 +TAN(val)           Return tangent of val
   1.206 +ASN(val)           Return arc-sine of val
   1.207 +ACS(val)           Return arc-cosine of val
   1.208 +ATN(val)           Return arc-tangent of val
   1.209 +RAD(val)           Convert degrees to radians
   1.210 +DEG(val)           Convert radians to degrees
   1.211 +INT(val)           Round to integer (towards zero)
   1.212 +ABS(val)           Take the absolute value
   1.213 +SGN(val)           Return -1, 0 or 1, depending on the sign of the argument
   1.214 +RND(val)           RND(1) returns a random number between 0 and 1
   1.215 +                   RND(n) returns an integer between 0 and n-1
   1.216 +
   1.217 +Also, some constants are defined:
   1.218 +
   1.219 +PI                 The value of PI (3.1415927...)
   1.220 +FALSE              Returns 0
   1.221 +TRUE               Returns -1
   1.222 +* or P%            A special symbol which returns the current address being
   1.223 +                   assembled at.
   1.224 +
   1.225 +Variables can be defined at any point using the BASIC syntax, i.e.
   1.226 +addr = &70.
   1.227 +
   1.228 +Note that it is not possible to reassign variables once defined.
   1.229 +However FOR...NEXT blocks have their own scope (more on this later).
   1.230 +
   1.231 +
   1.232 +
   1.233 +
   1.234 +6. ASSEMBLER DIRECTIVES
   1.235 +
   1.236 +These are keywords which control the assembly of the source file.
   1.237 +Here's a summary:
   1.238 +
   1.239 +ORG <addr>
   1.240 +
   1.241 +Set the address to be assembled from.  This can be changed multiple times
   1.242 +during a source file if you wish (for example) to assemble two separate blocks
   1.243 +of code at different addresses, but share the labels between both blocks.
   1.244 +This is exactly equivalent to BBC BASIC's 'P%=<addr>'.
   1.245 +
   1.246 +
   1.247 +SKIP <bytes>
   1.248 +
   1.249 +Moves the address pointer on by the specified number of bytes.  Use this to
   1.250 +reserve a space of a fixed size in the code.
   1.251 +
   1.252 +
   1.253 +ALIGN <alignment>
   1.254 +
   1.255 +Used to align the address pointer to the next boundary, e.g. use ALIGN &100 to
   1.256 +move to the next page (useful perhaps for positioning a table at a page
   1.257 +boundary so that index accesses don't incur a "page crossed" penalty.
   1.258 +
   1.259 +
   1.260 +INCLUDE "filename"
   1.261 +
   1.262 +Includes the specified source file in the code at this point.
   1.263 +
   1.264 +
   1.265 +EQUB a [, b, c, ...]
   1.266 +
   1.267 +Insert the specified byte(s) into the code.  Note, unlike BBC BASIC, that a
   1.268 +comma-separated sequence can be inserted.
   1.269 +
   1.270 +
   1.271 +EQUW a [, b, c, ...]
   1.272 +
   1.273 +Insert the specified 16-bit word(s) into the code.
   1.274 +
   1.275 +
   1.276 +EQUS "string" [, "string", byte, ...]
   1.277 +
   1.278 +Inserts the specified string into the code.  Note that this can take a comma-
   1.279 +separated list of parameters which may also include bytes.  So, to zero-
   1.280 +terminate a string, you can write:
   1.281 +
   1.282 +            EQUS "My string", 0
   1.283 +
   1.284 +In fact, under the surface, there is no difference between EQUS and EQUB,
   1.285 +which is also able to take strings!
   1.286 +
   1.287 +
   1.288 +GUARD <addr>
   1.289 +
   1.290 +Puts a 'guard' on the specified address which will cause an error if you
   1.291 +attempt to assemble code over this address.
   1.292 +
   1.293 +
   1.294 +CLEAR <start>, <end>
   1.295 +
   1.296 +Clears all guards between the <start> and <end> addresses specified.  This can
   1.297 +also be used to reset a section of memory which has had code assembled in it
   1.298 +previously.  BeebAsm will complain if you attempt to assemble code over
   1.299 +previously assembled code at the same address without having saved the previous
   1.300 +code.
   1.301 +
   1.302 +
   1.303 +SAVE "filename", start, end [, exec]
   1.304 +
   1.305 +Saves out object code to either a DFS disc image (if one has been specified),
   1.306 +or to the current directory as a standalone file.  'exec' specifies the
   1.307 +execution address of the file when saved to a disc image.  A source file must
   1.308 +have at least one SAVE statement in it, otherwise nothing will be output.
   1.309 +BeebAsm will warn if this is the case.
   1.310 +
   1.311 +
   1.312 +PRINT
   1.313 +
   1.314 +Displays some text.  PRINT takes a comma-separated list of strings or values.
   1.315 +To print a value in hex, prefix the expression with a '~' character.
   1.316 +Examples:
   1.317 +
   1.318 +            PRINT "Value of label 'start' =", ~start
   1.319 +            PRINT "numdots =", numdots, "dottable size =", dotend-dotstart
   1.320 +
   1.321 +
   1.322 +FOR <var>, start, end [, step] ... NEXT
   1.323 +
   1.324 +I wanted this to have exactly the same syntax as BASIC, but I couldn't without
   1.325 +rewriting my expression parser, so we're stuck with this for now.
   1.326 +
   1.327 +It works exactly like BASIC's FOR...NEXT.  For example:
   1.328 +
   1.329 +            FOR n, 0, 10, 2    ; loop with n = 0, 2, 4, 6, 8, 10
   1.330 +              PRINT n
   1.331 +              LDA #0:STA &900+n
   1.332 +              LDA #n:STA &901+n
   1.333 +            NEXT
   1.334 +
   1.335 +The variable n only exists for the scope of the FOR...NEXT loop.
   1.336 +Also, any labels or variables defined within the loop are only visible within
   1.337 +it.  However, unlike BBC BASIC, forward references to labels inside the loop
   1.338 +will work properly, so, for example, this little multiply routine is perfectly
   1.339 +ok:
   1.340 +            .multiply
   1.341 +            \\ multiplies A*X, puts result in product/product+1
   1.342 +            CPX #0:BEQ zero
   1.343 +            DEX:STX product+1
   1.344 +            LSR A:STA product:LDA #0
   1.345 +            FOR n, 0, 7
   1.346 +              BCC skip:ADC product+1:.skip   \\ would break BBC BASIC!
   1.347 +              ROR A:ROR product
   1.348 +            NEXT
   1.349 +            STA product+1:RTS
   1.350 +            .zero
   1.351 +            STX product:STX product+1:RTS
   1.352 +
   1.353 +
   1.354 +IF...ELSE...ENDIF
   1.355 +
   1.356 +Use to assemble conditionally.  Like anything else in BeebAsm, these statements
   1.357 +can be placed on one line, separated by colons, but even if they are, ENDIF
   1.358 +must be present to denote the end of the IF block (unlike BBC BASIC).
   1.359 +
   1.360 +Examples of use:
   1.361 +
   1.362 +            \\ build a rather strange table
   1.363 +            FOR n, 0, 9
   1.364 +              IF (n AND 1) = 0
   1.365 +                a = n*n
   1.366 +              ELSE
   1.367 +                a = -n*n
   1.368 +              ENDIF
   1.369 +              EQUB a
   1.370 +            NEXT
   1.371 +
   1.372 +            IF debugraster:LDA #3:STA &FE21:ENDIF
   1.373 +
   1.374 +
   1.375 +
   1.376 +
   1.377 +7. TIPS AND TRICKS
   1.378 +
   1.379 +BeebAsm's approach of treating memory as a canvas which can be written to,
   1.380 +saved, and rewritten if desired makes it very easy to create certain types of
   1.381 +applications.
   1.382 +
   1.383 +Imagine wanting to create a program which used the BBC Micro's main RAM, plus
   1.384 +2 sideways RAM banks.  If there was executable code in main RAM and in both
   1.385 +banks, it's quite likely that you'd want to share label names amongst all of
   1.386 +these blocks of code, so that main RAM routines could page in the appropriate
   1.387 +RAM bank and call a routine in it, and likewise sideways RAM banks could call
   1.388 +routines in main RAM.
   1.389 +
   1.390 +Here's one way you could do that in BeebAsm:
   1.391 +
   1.392 +
   1.393 +    \\ Declare origin of main RAM code
   1.394 +    ORG &1100
   1.395 +
   1.396 +    \\ Put a guard at the start of screen
   1.397 +    GUARD &5800
   1.398 +
   1.399 +    .mainstart
   1.400 +      LDA #5:STA &FE30   ; page in RAM bank 2
   1.401 +      JSR bank2routine
   1.402 +      ...
   1.403 +    .mainroutine
   1.404 +      ...
   1.405 +    .mainend
   1.406 +
   1.407 +    SAVE "Main", mainstart, mainend, mainentry
   1.408 +
   1.409 +
   1.410 +    \\ Declare origin of bank 1 code
   1.411 +    ORG &8000
   1.412 +
   1.413 +    \\ Put a guard after the RAM bank so we don't stray over our boundary
   1.414 +    GUARD &C000
   1.415 +
   1.416 +    .bank1start
   1.417 +      ...
   1.418 +      JSR mainroutine
   1.419 +      ...
   1.420 +    .bank1end
   1.421 +
   1.422 +    SAVE "Bank1", bank1start, bank1end
   1.423 +
   1.424 +
   1.425 +    \\ Clear memory used by previous bank
   1.426 +    CLEAR &8000, &C000
   1.427 +
   1.428 +    \\ Declare origin of bank 2 code
   1.429 +    ORG &8000
   1.430 +
   1.431 +    \\ Put a guard after the RAM bank so we don't stray over our boundary
   1.432 +    GUARD &C000
   1.433 +
   1.434 +    .bank2start
   1.435 +      ...
   1.436 +    .bank2routine
   1.437 +      RTS
   1.438 +      ...
   1.439 +    .bank2end
   1.440 +
   1.441 +    SAVE "Bank2", bank2start, bank2end
   1.442 +
   1.443 +
   1.444 +Because all of this code is assembled in one session, label and variable names
   1.445 +persist across the assembly of all blocks of code.
   1.446 +
   1.447 +For tidiness, you could move the source code for each block of code into a
   1.448 +different file, and then just INCLUDE these in your main source file:
   1.449 +
   1.450 +    INCLUDE "main.asm"
   1.451 +    INCLUDE "bank1.asm"
   1.452 +    INCLUDE "bank2.asm"
   1.453 +
   1.454 +
   1.455 +
   1.456 +
   1.457 +8. DEMO
   1.458 +
   1.459 +There's a little assembler demo included called "demo.asm".
   1.460 +Build it with something like:
   1.461 +
   1.462 +      beebasm -i demo.asm -do demo.ssd -boot Code -v
   1.463 +
   1.464 +and it will create a bootable disc image.
   1.465 +
   1.466 +As well as demonstrating some of the features of BeebAsm (including building
   1.467 +lookup tables), it's also a fairly good demo of pushing the hardware to its
   1.468 +limits, in terms of creating a flicker-free animation, updating at 50Hz.
   1.469 +(This is not to say that it's particularly impressive, but nonetheless, it
   1.470 +really is pushing the hardware!!)
   1.471 +
   1.472 +
   1.473 +
   1.474 +
   1.475 +9. VERSION HISTORY
   1.476 +
   1.477 +16/12/2007  0.01  First released version.
   1.478 +
   1.479 +
   1.480 +
   1.481 +
   1.482 +10. REPORTING BUGS
   1.483 +
   1.484 +There are bound to be loads.  I wrote it quickly!  Please help me zap all the
   1.485 +problems by reporting any bugs to me, Rich Talbot-Watkins, at
   1.486 +rich_tw@hotmail.com
   1.487 +
   1.488 +Thank you!
     2.1 Binary file beebasm.exe has changed
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/demo.asm	Sat May 01 19:35:42 2010 +0100
     3.3 @@ -0,0 +1,479 @@
     3.4 +\ ******************************************************************
     3.5 +\ *
     3.6 +\ *		BeebAsm demo
     3.7 +\ *
     3.8 +\ *		Spinning star globe
     3.9 +\ *
    3.10 +\ *		Change the speed of rotation with Z and X keys
    3.11 +\ *		Press Esc to quit
    3.12 +\ *
    3.13 +\ *		Try assembling the code with debugrasters = TRUE (line 20)
    3.14 +\ *		It shows how the frame is split up into various stages of
    3.15 +\ *		processing.
    3.16 +\ *
    3.17 +\ *		The red part is where we start to plot the dots - starting as
    3.18 +\ *		soon before the first screenline of the next frame is rastered
    3.19 +\ *		as possible.
    3.20 +\ *
    3.21 +\ *		The magenta part is a small loop where we wait for 'vsync'.
    3.22 +\ *		It's not actually vsync, but in fact a fixed time from actual
    3.23 +\ *		vsync (timed by timer 1) from which point we can start to erase
    3.24 +\ *		points from the top of the screen down.
    3.25 +\ *
    3.26 +\ *		The blue part is the time when we are erasing dots.  Because
    3.27 +\ *		the dots are sorted from top to bottom of screen, we can
    3.28 +\ *		overlap these updates with the actual screen rasterisation.
    3.29 +\ *
    3.30 +\ ******************************************************************
    3.31 +
    3.32 +
    3.33 +\\ Define globals
    3.34 +
    3.35 +numdots			= 160
    3.36 +radius			= 100
    3.37 +timerlength		= 64*8*26
    3.38 +debugrasters	= FALSE
    3.39 +
    3.40 +
    3.41 +\\ Define some zp locations
    3.42 +
    3.43 +ORG 0
    3.44 +
    3.45 +.xpos			SKIP 1
    3.46 +.ypos			SKIP 1
    3.47 +.colour			SKIP 1
    3.48 +.write			SKIP 2
    3.49 +.vsync			SKIP 1
    3.50 +.angle			SKIP 2
    3.51 +.speed			SKIP 2
    3.52 +.counter		SKIP 1
    3.53 +.temp			SKIP 1
    3.54 +.behindflag		SKIP 1
    3.55 +
    3.56 +
    3.57 +\\ Set start address
    3.58 +
    3.59 +ORG &1100
    3.60 +
    3.61 +
    3.62 +\ ******************************************************************
    3.63 +\ *	The entry point of the demo
    3.64 +\ ******************************************************************
    3.65 +
    3.66 +.start
    3.67 +
    3.68 +	\\ Set up hardware state and interrupts
    3.69 +
    3.70 +	SEI
    3.71 +	LDX #&FF:TXS				; reset stack
    3.72 +	STX &FE44:STX &FE45
    3.73 +	LDA #&7F:STA &FE4E			; disable all interrupts
    3.74 +	STA &FE43					; set keyboard data direction
    3.75 +	LDA #&C2:STA &FE4E			; enable VSync and timer interrupt
    3.76 +	LDA #&0F:STA &FE42			; set addressable latch for writing
    3.77 +	LDA #3:STA &FE40			; keyboard write enable
    3.78 +	LDA #0:STA &FE4B			; timer 1 one shot mode
    3.79 +	LDA #LO(irq):STA &204
    3.80 +	LDA #HI(irq):STA &205		; set interrupt handler
    3.81 +
    3.82 +	\\ Clear the screen
    3.83 +
    3.84 +	LDX #&40
    3.85 +	LDA #0
    3.86 +	TAY
    3.87 +.clearloop
    3.88 +	STA &4000,Y
    3.89 +	INY
    3.90 +	BNE clearloop
    3.91 +	INC clearloop+2
    3.92 +	DEX
    3.93 +	BNE clearloop
    3.94 +
    3.95 +	\\ Set up CRTC for MODE 2
    3.96 +
    3.97 +	LDX #13
    3.98 +.crtcloop
    3.99 +	STX &FE00
   3.100 +	LDA crtcregs,X
   3.101 +	STA &FE01
   3.102 +	DEX
   3.103 +	BPL crtcloop
   3.104 +
   3.105 +	\\ Set up video ULA for MODE 2
   3.106 +
   3.107 +	LDA #&F4
   3.108 +	STA &FE20
   3.109 +
   3.110 +	\\ Set up palette for MODE 2
   3.111 +
   3.112 +	LDX #15
   3.113 +.palloop
   3.114 +	LDA paldata,X
   3.115 +	STA &FE21
   3.116 +	ORA #&80
   3.117 +	STA &FE21
   3.118 +	DEX
   3.119 +	BPL palloop
   3.120 +
   3.121 +	\\ Initialise vars
   3.122 +
   3.123 +	LDA #0:STA angle:STA angle+1
   3.124 +	STA vsync
   3.125 +	STA speed
   3.126 +	LDA #1:STA speed+1
   3.127 +
   3.128 +	\\ Enable interrupts, ready to start the main loop
   3.129 +
   3.130 +	CLI
   3.131 +
   3.132 +	\\ First we wait for 'vsync' so we are synchronised
   3.133 +
   3.134 +.initialwait
   3.135 +	LDA vsync:BEQ initialwait:LDA #0:STA vsync
   3.136 +
   3.137 +	\\ This is the main loop!
   3.138 +
   3.139 +.mainloop
   3.140 +
   3.141 +	\\ Plot every dot on the screen
   3.142 +
   3.143 +	LDX #0
   3.144 +.plotdotloop
   3.145 +	STX counter
   3.146 +
   3.147 +	; setup y pos ready for plot routine
   3.148 +
   3.149 +	LDA doty,X:STA ypos
   3.150 +
   3.151 +	; get sin index
   3.152 +
   3.153 +	CLC:LDA dotx,X:ADC angle+1:TAY
   3.154 +	CLC:ADC #64:STA behindflag
   3.155 +
   3.156 +	; get colour from sin index
   3.157 +
   3.158 +	LDA coltable,Y:STA colour
   3.159 +
   3.160 +	; perform sin(x) * radius
   3.161 +	; discussion of the multiplication method below in the table setup
   3.162 +
   3.163 +	SEC:LDA sintable,Y:STA temp:SBC dotr,X
   3.164 +	BCS noneg:EOR #&FF:ADC #1:.noneg
   3.165 +	CPY #128:TAY:BCS negativesine
   3.166 +
   3.167 +	CLC:LDA dotr,X:ADC temp:TAX
   3.168 +	BCS morethan256:SEC
   3.169 +	LDA multtab1,X:SBC multtab1,Y:JMP donemult
   3.170 +	.morethan256
   3.171 +	LDA multtab2,X:SBC multtab1,Y:JMP donemult
   3.172 +
   3.173 +	.negativesine
   3.174 +	CLC:LDA dotr,X:ADC temp:TAX
   3.175 +	BCS morethan256b:SEC
   3.176 +	LDA multtab1,Y:SBC multtab1,X:JMP donemult
   3.177 +	.morethan256b
   3.178 +	LDA multtab1,Y:SBC multtab2,X
   3.179 +	.donemult
   3.180 +
   3.181 +	CLC:ADC #64:STA xpos
   3.182 +
   3.183 +	; routine to plot a dot
   3.184 +	; also we remember the calculated screen address in the dot tables
   3.185 +
   3.186 +	LDA ypos:LSR A:LSR A:AND #&FE
   3.187 +	TAX
   3.188 +	LDA xpos:AND #&FE:ASL A:ASL A
   3.189 +	STA write
   3.190 +	LDY counter:STA olddotaddrlo,Y
   3.191 +	TXA:ADC #&40:STA write+1:STA olddotaddrhi,Y
   3.192 +	LDA ypos:AND #7:STA olddotaddry,Y:TAY
   3.193 +	LDA xpos:LSR A:LDA colour:ROL A:TAX
   3.194 +	LDA colours,X
   3.195 +	ORA (write),Y
   3.196 +	STA (write),Y
   3.197 +	BIT behindflag:BMI behind
   3.198 +
   3.199 +	; if the dot is in front, we double its size
   3.200 +
   3.201 +	DEY:BPL samescreenrow
   3.202 +	DEC write+1:DEC write+1:LDY #7:.samescreenrow
   3.203 +	LDA colours,X
   3.204 +	ORA (write),Y
   3.205 +	STA (write),Y
   3.206 +	.behind
   3.207 +
   3.208 +	; loop to the next dot
   3.209 +
   3.210 +	LDX counter
   3.211 +	INX:CPX #numdots
   3.212 +	BEQ waitforvsync
   3.213 +	JMP plotdotloop
   3.214 +
   3.215 +	\\ Wait for VSync here
   3.216 +
   3.217 +.waitforvsync
   3.218 +	IF debugrasters
   3.219 +		LDA #&00 + PAL_magenta:STA &FE21
   3.220 +	ENDIF
   3.221 +.waitingforvsync
   3.222 +	LDA vsync:BEQ waitingforvsync
   3.223 +	CMP #2:BCS exit		; insist that it runs in a frame!
   3.224 +	LDA #0:STA vsync
   3.225 +
   3.226 +	\\ Now delete all the old dots.
   3.227 +	\\ We actually do this when the screen is still rasterising down..!
   3.228 +
   3.229 +	TAX
   3.230 +.eraseloop
   3.231 +	LDY olddotaddrlo,X:STY write
   3.232 +	LDY olddotaddrhi,X:STY write+1
   3.233 +	LDY olddotaddry,X
   3.234 +	STA (write),Y
   3.235 +	DEY:BPL erasesamerow
   3.236 +	DEC write+1:DEC write+1:LDY #7:.erasesamerow
   3.237 +	STA (write),Y
   3.238 +	INX:CPX #numdots
   3.239 +	BNE eraseloop
   3.240 +
   3.241 +	IF debugrasters
   3.242 +		LDA #&00 + PAL_red:STA &FE21
   3.243 +	ENDIF
   3.244 +
   3.245 +	\\ Add to rotation
   3.246 +
   3.247 +	CLC:LDA angle:ADC speed:STA angle
   3.248 +	LDA angle+1:ADC speed+1:STA angle+1
   3.249 +
   3.250 +	\\ Check keypresses
   3.251 +
   3.252 +	LDA #66:STA &FE4F:LDA &FE4F:BPL notx
   3.253 +	CLC:LDA speed:ADC #16:STA speed:BCC notx:INC speed+1:.notx
   3.254 +	LDA #97:STA &FE4F:LDA &FE4F:BPL notz
   3.255 +	SEC:LDA speed:SBC #16:STA speed:BCS notz:DEC speed+1:.notz
   3.256 +	LDA #112:STA &FE4F:LDA &FE4F:BMI exit
   3.257 +
   3.258 +	JMP mainloop
   3.259 +
   3.260 +	\\ Exit - in the least graceful way possible :)
   3.261 +
   3.262 +.exit
   3.263 +	JMP (&FFFC)
   3.264 +
   3.265 +
   3.266 +
   3.267 +\ ******************************************************************
   3.268 +\ *	IRQ handler
   3.269 +\ ******************************************************************
   3.270 +
   3.271 +.irq
   3.272 +	LDA &FE4D:AND #2:BNE irqvsync
   3.273 +.irqtimer
   3.274 +	LDA #&40:STA &FE4D:INC vsync
   3.275 +	IF debugrasters
   3.276 +		LDA #&00 + PAL_blue:STA &FE21
   3.277 +	ENDIF
   3.278 +	LDA &FC
   3.279 +	RTI
   3.280 +.irqvsync
   3.281 +	STA &FE4D
   3.282 +	LDA #LO(timerlength):STA &FE44
   3.283 +	LDA #HI(timerlength):STA &FE45
   3.284 +	IF debugrasters
   3.285 +		LDA #&00 + PAL_black:STA &FE21
   3.286 +	ENDIF
   3.287 +	LDA &FC
   3.288 +	RTI
   3.289 +
   3.290 +
   3.291 +
   3.292 +\ ******************************************************************
   3.293 +\ *	Colour table used by the plot code
   3.294 +\ ******************************************************************
   3.295 +
   3.296 +.colours
   3.297 +	EQUB &00, &00		; black pixels
   3.298 +	EQUB &02, &01		; blue pixels
   3.299 +	EQUB &08, &04		; red pixels
   3.300 +	EQUB &0A, &05		; magenta pixels
   3.301 +	EQUB &20, &10		; green pixels
   3.302 +	EQUB &22, &11		; cyan pixels
   3.303 +	EQUB &28, &14		; yellow pixels
   3.304 +	EQUB &2A, &15		; white pixels
   3.305 +
   3.306 +
   3.307 +
   3.308 +\ ******************************************************************
   3.309 +\ *	Values of CRTC regs for MODE 2
   3.310 +\ ******************************************************************
   3.311 +
   3.312 +.crtcregs
   3.313 +	EQUB 127			; R0  horizontal total
   3.314 +	EQUB 64				; R1  horizontal displayed - shrunk a little
   3.315 +	EQUB 91				; R2  horizontal position
   3.316 +	EQUB 40				; R3  sync width
   3.317 +	EQUB 38				; R4  vertical total
   3.318 +	EQUB 0				; R5  vertical total adjust
   3.319 +	EQUB 32				; R6  vertical displayed
   3.320 +	EQUB 34				; R7  vertical position
   3.321 +	EQUB 0				; R8  interlace
   3.322 +	EQUB 7				; R9  scanlines per row
   3.323 +	EQUB 32				; R10 cursor start
   3.324 +	EQUB 8				; R11 cursor end
   3.325 +	EQUB HI(&4000/8)	; R12 screen start address, high
   3.326 +	EQUB LO(&4000/8)	; R13 screen start address, low
   3.327 +
   3.328 +
   3.329 +\ ******************************************************************
   3.330 +\ *	Values of palette regs for MODE 2
   3.331 +\ ******************************************************************
   3.332 +
   3.333 +PAL_black	= (0 EOR 7)
   3.334 +PAL_blue	= (4 EOR 7)
   3.335 +PAL_red		= (1 EOR 7)
   3.336 +PAL_magenta = (5 EOR 7)
   3.337 +PAL_green	= (2 EOR 7)
   3.338 +PAL_cyan	= (6 EOR 7)
   3.339 +PAL_yellow	= (3 EOR 7)
   3.340 +PAL_white	= (7 EOR 7)
   3.341 +
   3.342 +.paldata
   3.343 +	EQUB &00 + PAL_black
   3.344 +	EQUB &10 + PAL_blue
   3.345 +	EQUB &20 + PAL_red
   3.346 +	EQUB &30 + PAL_magenta
   3.347 +	EQUB &40 + PAL_green
   3.348 +	EQUB &50 + PAL_cyan
   3.349 +	EQUB &60 + PAL_yellow
   3.350 +	EQUB &70 + PAL_white
   3.351 +
   3.352 +
   3.353 +
   3.354 +\ ******************************************************************
   3.355 +\ *	sin table
   3.356 +\ ******************************************************************
   3.357 +
   3.358 +; contains ABS sine values
   3.359 +; we don't store the sign as it confuses the multiplication.
   3.360 +; we can tell the sign very easily from whether the index is >128
   3.361 +
   3.362 +ALIGN &100	; so we don't incur page-crossed penalties
   3.363 +.sintable
   3.364 +FOR n, 0, 255
   3.365 +	EQUB ABS(SIN(n/128*PI)) * 255
   3.366 +NEXT
   3.367 +
   3.368 +
   3.369 +\ ******************************************************************
   3.370 +\ *	colour table
   3.371 +\ ******************************************************************
   3.372 +
   3.373 +ALIGN &100
   3.374 +.coltable
   3.375 +FOR n, 0, 255
   3.376 +	EQUB (SIN(n/128*PI) + 1) / 2.0001 * 7 + 1
   3.377 +NEXT
   3.378 +
   3.379 +
   3.380 +\ ******************************************************************
   3.381 +\ *	multiplication tables
   3.382 +\ ******************************************************************
   3.383 +
   3.384 +; This is a very quick way to do multiplies, based on the fact that:
   3.385 +;
   3.386 +;							(a+b)^2  =  a^2 + b^2 + 2ab    (I)
   3.387 +;							(a-b)^2  =  a^2 + b^2 - 2ab    (II)
   3.388 +;
   3.389 +; (I) minus (II) yields:	(a+b)^2 - (a-b)^2 = 4ab
   3.390 +;
   3.391 +; 		  or, rewritten:	ab = f(a+b) - f(a-b),
   3.392 +;											where f(x) = x^2 / 4
   3.393 +;
   3.394 +; We build a table of f(x) here with x=0..511, and then can perform
   3.395 +; 8-bit * 8-bit by 4 table lookups and a 16-bit subtract.
   3.396 +;
   3.397 +; In this case, we will discard the low byte of the result, so we
   3.398 +; only need the high bytes, and can do just 2 table lookups and a
   3.399 +; simple 8-bit subtract.
   3.400 +
   3.401 +ALIGN &100
   3.402 +.multtab1
   3.403 +FOR n, 0, 255
   3.404 +	EQUB HI(n*n DIV 4)
   3.405 +NEXT
   3.406 +.multtab2
   3.407 +FOR n, 256, 511
   3.408 +	EQUB HI(n*n DIV 4)
   3.409 +NEXT
   3.410 +
   3.411 +
   3.412 +\ ******************************************************************
   3.413 +\ *	dot tables
   3.414 +\ ******************************************************************
   3.415 +
   3.416 +; contains the phase of this dot
   3.417 +
   3.418 +ALIGN &100
   3.419 +.dotx
   3.420 +FOR n, 0, numdots-1
   3.421 +	EQUB RND(256)
   3.422 +NEXT
   3.423 +
   3.424 +
   3.425 +; contains the y position of the dot
   3.426 +; the dots are sorted by y positions, highest on screen first - this means we can do
   3.427 +; 'raster chasing'!
   3.428 +; the y positions are also biased so there are fewer at the poles, and more at the equator!
   3.429 +
   3.430 +ALIGN &100
   3.431 +.doty
   3.432 +FOR n, 0, numdots-1
   3.433 +	x = (n - numdots/2 + 0.5) / (numdots/2)
   3.434 +	y = (x - SIN(x*PI) * 0.1) * radius
   3.435 +	EQUB 128 + y
   3.436 +NEXT
   3.437 +
   3.438 +
   3.439 +; contains the radius of the ball at this y position
   3.440 +
   3.441 +ALIGN &100
   3.442 +.dotr
   3.443 +FOR n, 0, numdots-1
   3.444 +	x = (n - numdots/2 + 0.5) / (numdots/2)
   3.445 +	y = (x - SIN(x*PI) * 0.1) * radius
   3.446 +	r = SQR(radius*radius - y*y) / 2
   3.447 +	EQUB r
   3.448 +NEXT
   3.449 +
   3.450 +
   3.451 +\ ******************************************************************
   3.452 +\ *	End address to be saved
   3.453 +\ ******************************************************************
   3.454 +.end
   3.455 +
   3.456 +
   3.457 +
   3.458 +\ ******************************************************************
   3.459 +\ *	Space reserved for tables but not initialised with anything
   3.460 +\ * Therefore these are not saved in the executable
   3.461 +\ ******************************************************************
   3.462 +
   3.463 +; these store the screen address of the last dot
   3.464 +; at the end of the frame, we go through these tables, storing zeroes to
   3.465 +; all these addresses in order to delete the last frame
   3.466 +
   3.467 +ALIGN &100
   3.468 +.olddotaddrlo	SKIP numdots
   3.469 +
   3.470 +ALIGN &100
   3.471 +.olddotaddrhi	SKIP numdots
   3.472 +
   3.473 +ALIGN &100
   3.474 +.olddotaddry	SKIP numdots
   3.475 +
   3.476 +
   3.477 +
   3.478 +\ ******************************************************************
   3.479 +\ *	Save the code
   3.480 +\ ******************************************************************
   3.481 +
   3.482 +SAVE "Code", start, end
     4.1 Binary file demo.ssd has changed
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/Makefile	Sat May 01 19:35:42 2010 +0100
     5.3 @@ -0,0 +1,44 @@
     5.4 +#**************************************************************************************************
     5.5 +#
     5.6 +#	Makefile for beebasm
     5.7 +#
     5.8 +#**************************************************************************************************
     5.9 +
    5.10 +# List source subdirectories
    5.11 +
    5.12 +DIRS			:=
    5.13 +
    5.14 +# Define object file path
    5.15 +
    5.16 +BUILD_DIR		:=		./objects
    5.17 +
    5.18 +# Define target file
    5.19 +
    5.20 +TARGET			:=		../beebasm.exe
    5.21 +
    5.22 +# Define compiler switches
    5.23 +
    5.24 +WARNFLAGS		:=		-Wall -W -Wcast-qual -Werror -Wshadow -Wcast-align -Wold-style-cast -Woverloaded-virtual
    5.25 +CXXFLAGS		:=		-O3 -pedantic $(WARNFLAGS)
    5.26 +
    5.27 +# Define linker switches
    5.28 +
    5.29 +LDFLAGS			:=		-s
    5.30 +
    5.31 +# Define 2nd party libs to link
    5.32 +
    5.33 +LOADLIBES		:=
    5.34 +
    5.35 +# Define GNU libs to link
    5.36 +
    5.37 +LDLIBS			:=		-lstdc++
    5.38 +
    5.39 +# Parameters to the executable
    5.40 +
    5.41 +PARAMS			:=		-i ..\demo.asm -do ..\demo.ssd -boot Code
    5.42 +
    5.43 +
    5.44 +
    5.45 +#--------------------------------------------------------------------------------------------------
    5.46 +
    5.47 +include Makefile.inc
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/Makefile.inc	Sat May 01 19:35:42 2010 +0100
     6.3 @@ -0,0 +1,184 @@
     6.4 +#**************************************************************************************************
     6.5 +#
     6.6 +#	Standard Makefile core v1.0
     6.7 +#
     6.8 +#	This builds all .cpp and .c files it finds within the current directory and any specified
     6.9 +#	subdirectories, handling dependencies automatically, and outputs the specified executable.
    6.10 +#
    6.11 +#	This requires the following to be defined:
    6.12 +#
    6.13 +#		BUILD_DIR		Path into which objects are compiled
    6.14 +#		TARGET			Name of final executable
    6.15 +#
    6.16 +#	Additionally the following may be defined:
    6.17 +#
    6.18 +#		DIRS			Any subdirectories containing additional source files
    6.19 +#		CFLAGS			Any flags to be passed to the C compiler
    6.20 +#		CXXFLAGS		Any flags to be passed to the C++ compiler
    6.21 +#		LDFLAGS			Any flags to be passed to the linker
    6.22 +#		LOADLIBES		Any 2nd party libraries to be linked with
    6.23 +#		LDLIBS			Any GNU libraries to be linked with
    6.24 +#		CPUS			The number of CPUs on this machine
    6.25 +#		VERBOSE			Echoes all commands launched by make
    6.26 +#
    6.27 +#	@author camrtw
    6.28 +#
    6.29 +#**************************************************************************************************
    6.30 +
    6.31 +# Check that required variables have been set
    6.32 +
    6.33 +ifndef BUILD_DIR
    6.34 +error Please set BUILD_DIR to the path into which objects are compiled
    6.35 +endif
    6.36 +
    6.37 +ifndef TARGET
    6.38 +error Please set TARGET to the filename of the final executable to be built
    6.39 +endif
    6.40 +
    6.41 +
    6.42 +# Get list of subdirectories
    6.43 +
    6.44 +DIRS			:=		$(sort . $(DIRS))
    6.45 +
    6.46 +
    6.47 +# Automatically build list of source files
    6.48 +
    6.49 +SRCS			:=		$(wildcard $(addsuffix /*.cpp,$(DIRS)) $(addsuffix /*.c,$(DIRS)))
    6.50 +
    6.51 +
    6.52 +# Get list of object/dep files from source files
    6.53 +
    6.54 +OBJS			:=		$(subst /./,/,$(patsubst %.cpp,$(BUILD_DIR)/%.o,$(SRCS)))
    6.55 +DEPS			:=		$(OBJS:.o=.d)
    6.56 +
    6.57 +
    6.58 +# Declare executable names
    6.59 +
    6.60 +CC				:=		C:/MinGW/bin/gcc
    6.61 +CXX				:=		C:/MinGW/bin/gcc
    6.62 +LD				:=		C:/MinGW/bin/gcc
    6.63 +MKDIR			:=		C:/Utilities/mkdir -p
    6.64 +RM				:=		C:/Utilities/rm -f
    6.65 +ECHO			:=		@@C:/Utilities/echo
    6.66 +
    6.67 +
    6.68 +# Declare default number of CPUs
    6.69 +
    6.70 +CPUS			?=		1
    6.71 +
    6.72 +
    6.73 +# Set variables according to VERBOSE
    6.74 +
    6.75 +ifdef VERBOSE
    6.76 +VB				:=
    6.77 +VB_MAKE			:=
    6.78 +else
    6.79 +VB				:=		@@
    6.80 +VB_MAKE			:=		-s
    6.81 +endif
    6.82 +
    6.83 +
    6.84 +
    6.85 +#--------------------------------------------------------------------------------------------------
    6.86 +#	Rules/targets
    6.87 +
    6.88 +
    6.89 +.PHONY: folders all code deps objs run clean help
    6.90 +
    6.91 +
    6.92 +help:
    6.93 +	$(ECHO) Possible options:
    6.94 +	$(ECHO) make all .... Build and run code
    6.95 +	$(ECHO) make code ... Build code
    6.96 +	$(ECHO) make run .... Run code
    6.97 +	$(ECHO) make clean .. Clean code
    6.98 +	$(ECHO) make help ... Display this message again
    6.99 +	$(ECHO) Append VERBOSE=1 to show more information
   6.100 +
   6.101 +
   6.102 +folders: $(addprefix $(BUILD_DIR)/,$(DIRS))
   6.103 +
   6.104 +
   6.105 +objs: folders
   6.106 +	$(VB)$(MAKE) $(VB_MAKE) -j $(CPUS) $(OBJS) INCLUDE_DEPS=1
   6.107 +
   6.108 +
   6.109 +deps: folders
   6.110 +	$(VB)$(MAKE) $(VB_MAKE) -j $(CPUS) $(DEPS) INCLUDE_DEPS=1
   6.111 +
   6.112 +
   6.113 +code: deps objs $(TARGET)
   6.114 +
   6.115 +
   6.116 +run:
   6.117 +	$(ECHO) Running ... $(TARGET)\n
   6.118 +	$(VB)$(TARGET) $(PARAMS)
   6.119 +
   6.120 +
   6.121 +all: code run
   6.122 +
   6.123 +
   6.124 +clean:
   6.125 +	$(ECHO) Cleaning target and objects...
   6.126 +	$(VB)$(RM) $(TARGET)
   6.127 +	$(VB)$(RM) -r $(BUILD_DIR)
   6.128 +
   6.129 +
   6.130 +
   6.131 +#--------------------------------------------------------------------------------------------------
   6.132 +#	Rules/targets
   6.133 +
   6.134 +
   6.135 +# Build dep file from C++ file
   6.136 +
   6.137 +$(BUILD_DIR)/%.d : %.cpp
   6.138 +	$(ECHO) Generating dependencies for ... $<
   6.139 +	$(VB)$(CXX) $(CXXFLAGS) -MM -MF $@ -MT $@ -MT $(@:.d=.o) -c $<
   6.140 +
   6.141 +
   6.142 +# Build dep file from C file
   6.143 +
   6.144 +$(BUILD_DIR)/%.d : %.c
   6.145 +	$(ECHO) Generating dependencies for ... $<
   6.146 +	$(VB)$(CC) $(CFLAGS) -MM -MF $@ -MT $@ -MT $(@:.d=.o) -c $<
   6.147 +
   6.148 +
   6.149 +# Build object from C++ file
   6.150 +
   6.151 +$(BUILD_DIR)/%.o : %.cpp
   6.152 +	$(ECHO) Compiling ... $<
   6.153 +	$(VB)$(CXX) $(CXXFLAGS) -c $< -o $@
   6.154 +ifdef OUTPUT_SOURCE
   6.155 +	$(VB)$(CXX) $(CXXFLAGS) -S $< -o $(@:.o=.s)
   6.156 +endif
   6.157 +
   6.158 +
   6.159 +# Build object from C file
   6.160 +
   6.161 +$(BUILD_DIR)/%.o : %.c
   6.162 +	$(ECHO) Compiling ... $<
   6.163 +	$(VB)$(CC) $(CFLAGS) -c $< -o $@
   6.164 +ifdef OUTPUT_SOURCE
   6.165 +	$(VB)$(CXX) $(CXXFLAGS) -S $< -o $(@:.o=.s)
   6.166 +endif
   6.167 +
   6.168 +
   6.169 +# Build target
   6.170 +
   6.171 +$(TARGET) : $(OBJS)
   6.172 +	$(ECHO) Linking ... $@
   6.173 +	$(VB)$(LD) $(LDFLAGS) -o $(TARGET) $(OBJS) $(LOADLIBES) $(LDLIBS)
   6.174 +
   6.175 +
   6.176 +# Create object subdirectory
   6.177 +
   6.178 +$(addprefix $(BUILD_DIR)/,$(DIRS)):
   6.179 +	$(ECHO) Making subdirectory ... $@
   6.180 +	$(VB)$(MKDIR) $@
   6.181 +
   6.182 +
   6.183 +# Include dependencies
   6.184 +
   6.185 +ifdef INCLUDE_DEPS
   6.186 +-include $(DEPS)
   6.187 +endif
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/asmexception.cpp	Sat May 01 19:35:42 2010 +0100
     7.3 @@ -0,0 +1,50 @@
     7.4 +/*************************************************************************************************/
     7.5 +/**
     7.6 +	asmexception.cpp
     7.7 +
     7.8 +	Exception handling for the app
     7.9 +*/
    7.10 +/*************************************************************************************************/
    7.11 +
    7.12 +#include <iostream>
    7.13 +#include <cassert>
    7.14 +
    7.15 +#include "asmexception.h"
    7.16 +#include "stringutils.h"
    7.17 +
    7.18 +using namespace std;
    7.19 +
    7.20 +
    7.21 +
    7.22 +/*************************************************************************************************/
    7.23 +/**
    7.24 +	AsmException_FileAccessError::Print()
    7.25 +
    7.26 +	Outputs to stderr an error message relating to an I/O exception
    7.27 +*/
    7.28 +/*************************************************************************************************/
    7.29 +void AsmException_FileError::Print() const
    7.30 +{
    7.31 +	cerr << "Error: " << m_pFilename << ": " << Message() << endl;
    7.32 +}
    7.33 +
    7.34 +
    7.35 +
    7.36 +/*************************************************************************************************/
    7.37 +/**
    7.38 +	AsmException_SyntaxError::Print()
    7.39 +
    7.40 +	Outputs to stderr an error message regarding a syntax error
    7.41 +*/
    7.42 +/*************************************************************************************************/
    7.43 +void AsmException_SyntaxError::Print() const
    7.44 +{
    7.45 +	assert( m_pFilename != NULL );
    7.46 +	assert( m_lineNumber != 0 );
    7.47 +
    7.48 +//	cerr << m_pFilename << ":" << m_lineNumber << ": error: ";
    7.49 +	cerr << Message() << endl << endl;
    7.50 +	cerr << m_line << endl;
    7.51 +	cerr << string( m_column, ' ' ) << "^" << endl;
    7.52 +}
    7.53 +
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/asmexception.h	Sat May 01 19:35:42 2010 +0100
     8.3 @@ -0,0 +1,241 @@
     8.4 +/*************************************************************************************************/
     8.5 +/**
     8.6 +	asmexception.h
     8.7 +*/
     8.8 +/*************************************************************************************************/
     8.9 +
    8.10 +#ifndef ASMEXCEPTION_H_
    8.11 +#define ASMEXCEPTION_H_
    8.12 +
    8.13 +
    8.14 +#include <string>
    8.15 +
    8.16 +
    8.17 +/*************************************************************************************************/
    8.18 +/**
    8.19 +	@class		AsmException
    8.20 +
    8.21 +	Base class for Asm6502 exceptions
    8.22 +*/
    8.23 +/*************************************************************************************************/
    8.24 +class AsmException
    8.25 +{
    8.26 +public:
    8.27 +
    8.28 +	AsmException() {}
    8.29 +
    8.30 +	virtual void Print() const = 0;
    8.31 +};
    8.32 +
    8.33 +
    8.34 +
    8.35 +/*************************************************************************************************/
    8.36 +/**
    8.37 +	@class		AsmException_FileError
    8.38 +
    8.39 +	Exception class used for all I/O errors
    8.40 +*/
    8.41 +/*************************************************************************************************/
    8.42 +class AsmException_FileError : public AsmException
    8.43 +{
    8.44 +public:
    8.45 +
    8.46 +	explicit AsmException_FileError( const char* pFilename )
    8.47 +		:	m_pFilename( pFilename )
    8.48 +	{
    8.49 +	}
    8.50 +
    8.51 +	virtual void Print() const;
    8.52 +
    8.53 +	virtual const char* Message() const
    8.54 +	{
    8.55 +		return "Unspecified file error.";
    8.56 +	}
    8.57 +
    8.58 +protected:
    8.59 +
    8.60 +	const char*			m_pFilename;
    8.61 +};
    8.62 +
    8.63 +
    8.64 +#define DEFINE_FILE_EXCEPTION( a, msg )										\
    8.65 +class AsmException_FileError_##a : public AsmException_FileError			\
    8.66 +{																			\
    8.67 +public:																		\
    8.68 +	explicit AsmException_FileError_##a( const char* pFilename )			\
    8.69 +		:	AsmException_FileError( pFilename ) {}							\
    8.70 +																			\
    8.71 +	virtual ~AsmException_FileError_##a() {}								\
    8.72 +																			\
    8.73 +	virtual const char* Message() const { return msg; }						\
    8.74 +}
    8.75 +
    8.76 +
    8.77 +DEFINE_FILE_EXCEPTION( OpenSourceFile, "Could not open source file for reading." );
    8.78 +DEFINE_FILE_EXCEPTION( ReadSourceFile, "Problem reading from source file." );
    8.79 +DEFINE_FILE_EXCEPTION( OpenDiscSource, "Could not open disc image for reading." );
    8.80 +DEFINE_FILE_EXCEPTION( ReadDiscSource, "Problem reading from disc image." );
    8.81 +DEFINE_FILE_EXCEPTION( OpenDiscDest, "Could not create new disc image." );
    8.82 +DEFINE_FILE_EXCEPTION( WriteDiscDest, "Could not write to disc image." );
    8.83 +DEFINE_FILE_EXCEPTION( OpenObj, "Could not open object file for writing." );
    8.84 +DEFINE_FILE_EXCEPTION( WriteObj, "Problem writing to object file." );
    8.85 +DEFINE_FILE_EXCEPTION( DiscFull, "No room on DFS disc image full." );
    8.86 +DEFINE_FILE_EXCEPTION( BadName, "Bad DFS filename." );
    8.87 +DEFINE_FILE_EXCEPTION( TooManyFiles, "Too many files on DFS disc image (max 31)." );
    8.88 +DEFINE_FILE_EXCEPTION( FileExists, "File already exists on DFS disc image." );
    8.89 +
    8.90 +
    8.91 +/*************************************************************************************************/
    8.92 +/**
    8.93 +	@class		AsmException_SyntaxError
    8.94 +
    8.95 +	Base exception class used for all syntax errors
    8.96 +*/
    8.97 +/*************************************************************************************************/
    8.98 +class AsmException_SyntaxError : public AsmException
    8.99 +{
   8.100 +public:
   8.101 +
   8.102 +	AsmException_SyntaxError()
   8.103 +		:	m_pFilename( NULL ),
   8.104 +			m_lineNumber( 0 )
   8.105 +	{
   8.106 +	}
   8.107 +
   8.108 +	AsmException_SyntaxError( std::string line, int column )
   8.109 +		:	m_line( line ),
   8.110 +			m_column( column ),
   8.111 +			m_pFilename( NULL ),
   8.112 +			m_lineNumber( 0 )
   8.113 +	{
   8.114 +	}
   8.115 +
   8.116 +	virtual ~AsmException_SyntaxError() {}
   8.117 +
   8.118 +	void SetFilename( const char* filename )	{ if ( m_pFilename == NULL ) m_pFilename = filename; }
   8.119 +	void SetLineNumber( int lineNumber )		{ if ( m_lineNumber == 0 ) m_lineNumber = lineNumber; }
   8.120 +
   8.121 +	virtual void Print() const;
   8.122 +	virtual const char* Message() const
   8.123 +	{
   8.124 +		return "Unspecified syntax error.";
   8.125 +	}
   8.126 +
   8.127 +
   8.128 +protected:
   8.129 +
   8.130 +	std::string			m_line;
   8.131 +	int					m_column;
   8.132 +	const char*			m_pFilename;
   8.133 +	int					m_lineNumber;
   8.134 +};
   8.135 +
   8.136 +
   8.137 +#define DEFINE_SYNTAX_EXCEPTION( a, msg )									\
   8.138 +class AsmException_SyntaxError_##a : public AsmException_SyntaxError		\
   8.139 +{																			\
   8.140 +public:																		\
   8.141 +	AsmException_SyntaxError_##a( std::string line, int column )			\
   8.142 +		:	AsmException_SyntaxError( line, column ) {}						\
   8.143 +																			\
   8.144 +	virtual ~AsmException_SyntaxError_##a() {}								\
   8.145 +																			\
   8.146 +	virtual const char* Message() const { return msg; }						\
   8.147 +}
   8.148 +
   8.149 +
   8.150 +// high-level file parsing exceptions
   8.151 +DEFINE_SYNTAX_EXCEPTION( UnrecognisedToken, "Unrecognised token." );
   8.152 +
   8.153 +// expression parsing exceptions
   8.154 +DEFINE_SYNTAX_EXCEPTION( NumberTooBig, "Number too big." );
   8.155 +DEFINE_SYNTAX_EXCEPTION( SymbolNotDefined, "Symbol not defined." );
   8.156 +DEFINE_SYNTAX_EXCEPTION( BadHex, "Bad hex." );
   8.157 +DEFINE_SYNTAX_EXCEPTION( MissingValue, "Missing value in expression." );
   8.158 +DEFINE_SYNTAX_EXCEPTION( InvalidCharacter, "Bad expression." );
   8.159 +DEFINE_SYNTAX_EXCEPTION( ExpressionTooComplex, "Expression too complex." );
   8.160 +DEFINE_SYNTAX_EXCEPTION( MismatchedParentheses, "Mismatched parentheses." );
   8.161 +DEFINE_SYNTAX_EXCEPTION( EmptyExpression, "Expression not found." );
   8.162 +DEFINE_SYNTAX_EXCEPTION( DivisionByZero, "Division by zero." );
   8.163 +DEFINE_SYNTAX_EXCEPTION( MissingQuote, "Unterminated string." );
   8.164 +DEFINE_SYNTAX_EXCEPTION( MissingComma, "Missing comma." );
   8.165 +DEFINE_SYNTAX_EXCEPTION( IllegalOperation, "Operation attempted with invalid or out of range values." );
   8.166 +
   8.167 +// assembler parsing exceptions
   8.168 +DEFINE_SYNTAX_EXCEPTION( NoImplied, "Implied mode not allowed for this instruction." );
   8.169 +DEFINE_SYNTAX_EXCEPTION( ImmTooLarge, "Immediate constants cannot be greater than 255." );
   8.170 +DEFINE_SYNTAX_EXCEPTION( ImmNegative, "Constant cannot be negative." );
   8.171 +DEFINE_SYNTAX_EXCEPTION( UnexpectedComma, "Unexpected comma enountered." );
   8.172 +DEFINE_SYNTAX_EXCEPTION( NoImmediate, "Immediate mode not allowed for this instruction." );
   8.173 +DEFINE_SYNTAX_EXCEPTION( NoIndirect16, "16-bit indirect mode not allowed for this instruction." );
   8.174 +DEFINE_SYNTAX_EXCEPTION( 6502Bug, "JMP (addr) will not execute as intended due to the 6502 bug (addr = &xxFF)." );
   8.175 +DEFINE_SYNTAX_EXCEPTION( BadIndirect, "Incorrectly formed indirect instruction." );
   8.176 +DEFINE_SYNTAX_EXCEPTION( NoIndirect, "Indirect mode not allowed for this instruction." );
   8.177 +DEFINE_SYNTAX_EXCEPTION( NotZeroPage, "Address is not in zero-page." );
   8.178 +DEFINE_SYNTAX_EXCEPTION( BranchOutOfRange, "Branch out of range." );
   8.179 +DEFINE_SYNTAX_EXCEPTION( NoAbsolute, "Absolute addressing mode not allowed for this instruction." );
   8.180 +DEFINE_SYNTAX_EXCEPTION( BadAbsolute, "Syntax error in absolute instruction." );
   8.181 +DEFINE_SYNTAX_EXCEPTION( BadIndexed, "Syntax error in indexed instruction." );
   8.182 +DEFINE_SYNTAX_EXCEPTION( NoIndexedX, "X indexed mode does not exist for this instruction." );
   8.183 +DEFINE_SYNTAX_EXCEPTION( NoIndexedY, "Y indexed mode does not exist for this instruction." );
   8.184 +DEFINE_SYNTAX_EXCEPTION( LabelAlreadyDefined, "Symbol already defined." );
   8.185 +DEFINE_SYNTAX_EXCEPTION( InvalidSymbolName, "Invalid symbol name; must start with a letter and contain only numbers and underscore." );
   8.186 +DEFINE_SYNTAX_EXCEPTION( SecondPassProblem, "Fatal error: the second assembler pass has generated different code to the first." );
   8.187 +
   8.188 +// meta-language parsing exceptions
   8.189 +DEFINE_SYNTAX_EXCEPTION( NextWithoutFor, "NEXT without FOR." );
   8.190 +DEFINE_SYNTAX_EXCEPTION( ForWithoutNext, "FOR without NEXT." );
   8.191 +DEFINE_SYNTAX_EXCEPTION( BadStep, "Step value cannot be zero." );
   8.192 +DEFINE_SYNTAX_EXCEPTION( TooManyFORs, "Too many nested FORs." );
   8.193 +DEFINE_SYNTAX_EXCEPTION( CantInclude, "Cannot include a source file within a FOR loop." );
   8.194 +DEFINE_SYNTAX_EXCEPTION( ElseWithoutIf, "ELSE without IF." );
   8.195 +DEFINE_SYNTAX_EXCEPTION( EndifWithoutIf, "ENDIF without IF." );
   8.196 +DEFINE_SYNTAX_EXCEPTION( IfWithoutEndif, "IF without ENDIF." );
   8.197 +DEFINE_SYNTAX_EXCEPTION( TooManyIFs, "Too many nested IFs." );
   8.198 +DEFINE_SYNTAX_EXCEPTION( BadAlignment, "Bad alignment." );
   8.199 +DEFINE_SYNTAX_EXCEPTION( OutOfRange, "Out of range." );
   8.200 +
   8.201 +
   8.202 +
   8.203 +/*************************************************************************************************/
   8.204 +/**
   8.205 +	@class		AsmException_AssembleError
   8.206 +
   8.207 +	Base exception class used for all assembling errors
   8.208 +*/
   8.209 +/*************************************************************************************************/
   8.210 +class AsmException_AssembleError : public AsmException_SyntaxError
   8.211 +{
   8.212 +public:
   8.213 +
   8.214 +	AsmException_AssembleError() {}
   8.215 +
   8.216 +	virtual ~AsmException_AssembleError() {}
   8.217 +
   8.218 +	void SetString( std::string line )			{ m_line = line; }
   8.219 +	void SetColumn( int column )				{ m_column = column; }
   8.220 +
   8.221 +	virtual const char* Message() const
   8.222 +	{
   8.223 +		return "Unspecified assemble error.";
   8.224 +	}
   8.225 +};
   8.226 +
   8.227 +
   8.228 +#define DEFINE_ASSEMBLE_EXCEPTION( a, msg )									\
   8.229 +class AsmException_AssembleError_##a : public AsmException_AssembleError	\
   8.230 +{																			\
   8.231 +public:																		\
   8.232 +	AsmException_AssembleError_##a() {}										\
   8.233 +	virtual ~AsmException_AssembleError_##a() {}							\
   8.234 +	virtual const char* Message() const { return msg; }						\
   8.235 +}
   8.236 +
   8.237 +
   8.238 +DEFINE_ASSEMBLE_EXCEPTION( OutOfMemory, "Out of memory." );
   8.239 +DEFINE_ASSEMBLE_EXCEPTION( GuardHit, "Guard point hit." );
   8.240 +DEFINE_ASSEMBLE_EXCEPTION( Overlap, "Trying to assemble over existing code." );
   8.241 +DEFINE_ASSEMBLE_EXCEPTION( InconsistentCode, "Assembled object code has changed between 1st and 2nd pass. Has a zero-page symbol been forward-declared?" );
   8.242 +
   8.243 +
   8.244 +#endif // ASMEXCEPTION_H_
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/assemble.cpp	Sat May 01 19:35:42 2010 +0100
     9.3 @@ -0,0 +1,746 @@
     9.4 +/*************************************************************************************************/
     9.5 +/**
     9.6 +	assemble.cpp
     9.7 +
     9.8 +	Contains all the LineParser methods for assembling code
     9.9 +*/
    9.10 +/*************************************************************************************************/
    9.11 +
    9.12 +#include <iostream>
    9.13 +#include <iomanip>
    9.14 +
    9.15 +#include "lineparser.h"
    9.16 +#include "globaldata.h"
    9.17 +#include "objectcode.h"
    9.18 +#include "asmexception.h"
    9.19 +
    9.20 +
    9.21 +using namespace std;
    9.22 +
    9.23 +
    9.24 +
    9.25 +#define DATA( op, imp, acc, imm, zp, zpx, zpy, abs, absx, absy, indx, indy, ind16, rel )  \
    9.26 +	{ { imp, acc, imm, zp, zpx, zpy, abs, absx, absy, indx, indy, ind16, rel }, op }
    9.27 +
    9.28 +#define X -1
    9.29 +
    9.30 +LineParser::OpcodeData	LineParser::m_gaOpcodeTable[] =
    9.31 +{
    9.32 +//					IMP		ACC		IMM		ZP		ZPX		ZPY		ABS		ABSX	ABSY	INDX	INDY	IND16	REL
    9.33 +
    9.34 +	DATA( "ADC",	 X,		 X,		0x69,	0x65,	0x75,	 X,		0x6D,	0x7D,	0x79,	0x61,	0x71,	 X,		 X		),
    9.35 +	DATA( "AND",	 X,		 X,		0x29,	0x25,	0x35,	 X,		0x2D,	0x3D,	0x39,	0x21,	0x31,	 X,		 X		),
    9.36 +	DATA( "ASL",	 X,		0x0A,	 X,		0x06,	0x16,	 X,		0x0E,	0x1E,	 X,		 X,		 X,		 X,		 X		),
    9.37 +	DATA( "BCC",	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		0x90	),
    9.38 +	DATA( "BCS",	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		0xB0	),
    9.39 +	DATA( "BEQ",	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		0xF0	),
    9.40 +	DATA( "BIT",	 X,		 X,		 X,		0x24,	 X,		 X,		0x2C,	 X,		 X,		 X,		 X,		 X,		 X		),
    9.41 +	DATA( "BMI",	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		0x30	),
    9.42 +	DATA( "BNE",	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		0xD0	),
    9.43 +	DATA( "BPL",	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		0x10	),
    9.44 +	DATA( "BRK",	0x00,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.45 +	DATA( "BVC",	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		0x50	),
    9.46 +	DATA( "BVS",	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		0x70	),
    9.47 +	DATA( "CLC",	0x18,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.48 +	DATA( "CLD",	0xD8,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.49 +	DATA( "CLI",	0x58,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.50 +	DATA( "CLV",	0xB8,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.51 +	DATA( "CMP",	 X,		 X,		0xC9,	0xC5,	0xD5,	 X,		0xCD,	0xDD,	0xD9,	0xC1,	0xD1,	 X,		 X		),
    9.52 +	DATA( "CPX",	 X,		 X,		0xE0,	0xE4,	 X,		 X,		0xEC,	 X,		 X,		 X,		 X,		 X,		 X		),
    9.53 +	DATA( "CPY",	 X,		 X,		0xC0,	0xC4,	 X,		 X,		0xCC,	 X,		 X,		 X,		 X,		 X,		 X		),
    9.54 +	DATA( "DEC",	 X,		 X,		 X,		0xC6,	0xD6,	 X,		0xCE,	0xDE,	 X,		 X,		 X,		 X,		 X		),
    9.55 +	DATA( "DEX",	0xCA,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.56 +	DATA( "DEY",	0x88,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.57 +	DATA( "EOR",	 X,		 X,		0x49,	0x45,	0x55,	 X,		0x4D,	0x5D,	0x59,	0x41,	0x51,	 X,		 X		),
    9.58 +	DATA( "INC",	 X,		 X,		 X,		0xE6,	0xF6,	 X,		0xEE,	0xFE,	 X,		 X,		 X,		 X,		 X		),
    9.59 +	DATA( "INX",	0xE8,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.60 +	DATA( "INY",	0xC8,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.61 +	DATA( "JMP",	 X,		 X,		 X,		 X,		 X,		 X,		0x4C,	 X,		 X,		 X,		 X,		0x6C,	 X		),
    9.62 +	DATA( "JSR",	 X,		 X,		 X,		 X,		 X,		 X,		0x20,	 X,		 X,		 X,		 X,		 X,		 X		),
    9.63 +	DATA( "LDA",	 X,		 X,		0xA9,	0xA5,	0xB5,	 X,		0xAD,	0xBD,	0xB9,	0xA1,	0xB1,	 X,		 X		),
    9.64 +	DATA( "LDX",	 X,		 X,		0xA2,	0xA6,	 X,		0xB6,	0xAE,	 X,		0xBE,	 X,		 X,		 X,		 X		),
    9.65 +	DATA( "LDY",	 X,		 X,		0xA0,	0xA4,	0xB4,	 X,		0xAC,	0xBC,	 X,		 X,		 X,		 X,		 X		),
    9.66 +	DATA( "LSR",	 X,		0x4A,	 X,		0x46,	0x56,	 X,		0x4E,	0x5E,	 X,		 X,		 X,		 X,		 X		),
    9.67 +	DATA( "NOP",	0xEA,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.68 +	DATA( "ORA",	 X,		 X,		0x09,	0x05,	0x15,	 X,		0x0D,	0x1D,	0x19,	0x01,	0x11,	 X,		 X		),
    9.69 +	DATA( "PHA",	0x48,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.70 +	DATA( "PHP",	0x08,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.71 +	DATA( "PLA",	0x68,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.72 +	DATA( "PLP",	0x28,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.73 +	DATA( "ROL",	 X,		0x2A,	 X,		0x26,	0x36,	 X,		0x2E,	0x3E,	 X,		 X,		 X,		 X,		 X		),
    9.74 +	DATA( "ROR",	 X,		0x6A,	 X,		0x66,	0x76,	 X,		0x6E,	0x7E,	 X,		 X,		 X,		 X,		 X		),
    9.75 +	DATA( "RTI",	0x40,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.76 +	DATA( "RTS",	0x60,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.77 +	DATA( "SBC",	 X,		 X,		0xE9,	0xE5,	0xF5,	 X,		0xED,	0xFD,	0xF9,	0xE1,	0xF1,	 X,		 X		),
    9.78 +	DATA( "SEC",	0x38,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.79 +	DATA( "SED",	0xF8,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.80 +	DATA( "SEI",	0x78,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.81 +	DATA( "STA",	 X,		 X,		 X,		0x85,	0x95,	 X,		0x8D,	0x9D,	0x99,	0x81,	0x91,	 X,		 X		),
    9.82 +	DATA( "STX",	 X,		 X,		 X,		0x86,	 X,		0x96,	0x8E,	 X,		 X,		 X,		 X,		 X,		 X		),
    9.83 +	DATA( "STY",	 X,		 X,		 X,		0x84,	0x94,	 X,		0x8C,	 X,		 X,		 X,		 X,		 X,		 X		),
    9.84 +	DATA( "TAX",	0xAA,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.85 +	DATA( "TAY",	0xA8,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.86 +	DATA( "TSX",	0xBA,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.87 +	DATA( "TXA",	0x8A,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.88 +	DATA( "TXS",	0x9A,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		),
    9.89 +	DATA( "TYA",	0x98,	 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X,		 X		)
    9.90 +};
    9.91 +
    9.92 +
    9.93 +
    9.94 +/*************************************************************************************************/
    9.95 +/**
    9.96 +	LineParser::GetInstructionAndAdvanceColumn()
    9.97 +
    9.98 +	Searches for an instruction match in the current line, starting at the current column,
    9.99 +	and moves the column pointer past the token
   9.100 +
   9.101 +	@param		line			The string to parse
   9.102 +	@param		column			The column to start from
   9.103 +
   9.104 +	@return		The token number, or -1 for "not found"
   9.105 +				column is modified to index the character after the token
   9.106 +*/
   9.107 +/*************************************************************************************************/
   9.108 +int LineParser::GetInstructionAndAdvanceColumn()
   9.109 +{
   9.110 +	for ( int i = 0; i < static_cast<int>( sizeof m_gaOpcodeTable / sizeof( OpcodeData ) ); i++ )
   9.111 +	{
   9.112 +		const char*	token	= m_gaOpcodeTable[ i ].m_pName;
   9.113 +		size_t		len		= strlen( token );
   9.114 +
   9.115 +		// create lower-case version of token
   9.116 +
   9.117 +		char tokenLC[ 16 ];
   9.118 +
   9.119 +		for ( size_t j = 0; j <= len; j++ )
   9.120 +		{
   9.121 +			tokenLC[ j ] = tolower( token[ j ] );
   9.122 +		}
   9.123 +
   9.124 +		// see if token matches
   9.125 +
   9.126 +		if ( m_line.compare( m_column, len, token ) == 0 ||
   9.127 +			 m_line.compare( m_column, len, tokenLC ) == 0 )
   9.128 +		{
   9.129 +			m_column += len;
   9.130 +			return i;
   9.131 +		}
   9.132 +	}
   9.133 +
   9.134 +	return -1;
   9.135 +}
   9.136 +
   9.137 +
   9.138 +
   9.139 +/*************************************************************************************************/
   9.140 +/**
   9.141 +	LineParser::HasAddressingMode()
   9.142 +*/
   9.143 +/*************************************************************************************************/
   9.144 +bool LineParser::HasAddressingMode( int instructionIndex, ADDRESSING_MODE mode )
   9.145 +{
   9.146 +	return ( m_gaOpcodeTable[ instructionIndex ].m_aOpcodes[ mode ] != -1 );
   9.147 +}
   9.148 +
   9.149 +
   9.150 +
   9.151 +/*************************************************************************************************/
   9.152 +/**
   9.153 +	LineParser::GetOpcode()
   9.154 +*/
   9.155 +/*************************************************************************************************/
   9.156 +unsigned int LineParser::GetOpcode( int instructionIndex, ADDRESSING_MODE mode )
   9.157 +{
   9.158 +	int i = m_gaOpcodeTable[ instructionIndex ].m_aOpcodes[ mode ];
   9.159 +
   9.160 +	assert( i != -1 );
   9.161 +	return static_cast< unsigned int >( i );
   9.162 +}
   9.163 +
   9.164 +
   9.165 +
   9.166 +/*************************************************************************************************/
   9.167 +/**
   9.168 +	LineParser::Assemble1()
   9.169 +*/
   9.170 +/*************************************************************************************************/
   9.171 +void LineParser::Assemble1( int instructionIndex, ADDRESSING_MODE mode )
   9.172 +{
   9.173 +	assert( HasAddressingMode( instructionIndex, mode ) );
   9.174 +
   9.175 +	if ( GlobalData::Instance().ShouldOutputAsm() )
   9.176 +	{
   9.177 +		cout << uppercase << hex << setfill( '0' ) << "     ";
   9.178 +		cout << setw(4) << ObjectCode::Instance().GetPC() << "   ";
   9.179 +		cout << setw(2) << GetOpcode( instructionIndex, mode ) << "         ";
   9.180 +		cout << m_gaOpcodeTable[ instructionIndex ].m_pName;
   9.181 +
   9.182 +		if ( mode == ACC )
   9.183 +		{
   9.184 +			cout << " A";
   9.185 +		}
   9.186 +
   9.187 +		cout << endl << nouppercase << dec << setfill( ' ' );
   9.188 +	}
   9.189 +
   9.190 +	try
   9.191 +	{
   9.192 +		ObjectCode::Instance().Assemble1( GetOpcode( instructionIndex, mode ) );
   9.193 +	}
   9.194 +	catch ( AsmException_AssembleError& e )
   9.195 +	{
   9.196 +		e.SetString( m_line );
   9.197 +		e.SetColumn( m_column );
   9.198 +		throw;
   9.199 +	}
   9.200 +}
   9.201 +
   9.202 +
   9.203 +
   9.204 +/*************************************************************************************************/
   9.205 +/**
   9.206 +	LineParser::Assemble2()
   9.207 +*/
   9.208 +/*************************************************************************************************/
   9.209 +void LineParser::Assemble2( int instructionIndex, ADDRESSING_MODE mode, unsigned int value )
   9.210 +{
   9.211 +	assert( value < 0x100 );
   9.212 +	assert( HasAddressingMode( instructionIndex, mode ) );
   9.213 +
   9.214 +	if ( GlobalData::Instance().ShouldOutputAsm() )
   9.215 +	{
   9.216 +		cout << uppercase << hex << setfill( '0' ) << "     ";
   9.217 +		cout << setw(4) << ObjectCode::Instance().GetPC() << "   ";
   9.218 +		cout << setw(2) << GetOpcode( instructionIndex, mode ) << " ";
   9.219 +		cout << setw(2) << value << "      ";
   9.220 +		cout << m_gaOpcodeTable[ instructionIndex ].m_pName << " ";
   9.221 +
   9.222 +		if ( mode == IMM )
   9.223 +		{
   9.224 +			cout << "#";
   9.225 +		}
   9.226 +		else if ( mode == INDX || mode == INDY )
   9.227 +		{
   9.228 +			cout << "(";
   9.229 +		}
   9.230 +
   9.231 +		if ( mode == REL )
   9.232 +		{
   9.233 +			cout << "&" << setw(4) << ObjectCode::Instance().GetPC() + 2 + static_cast< signed char >( value );
   9.234 +		}
   9.235 +		else
   9.236 +		{
   9.237 +			cout << "&" << setw(2) << value;
   9.238 +		}
   9.239 +
   9.240 +		if ( mode == ZPX )
   9.241 +		{
   9.242 +			cout << ",X";
   9.243 +		}
   9.244 +		else if ( mode == ZPY )
   9.245 +		{
   9.246 +			cout << ",Y";
   9.247 +		}
   9.248 +		else if ( mode == INDX )
   9.249 +		{
   9.250 +			cout << ",X)";
   9.251 +		}
   9.252 +		else if ( mode == INDY )
   9.253 +		{
   9.254 +			cout << "),Y";
   9.255 +		}
   9.256 +
   9.257 +		cout << endl << nouppercase << dec << setfill( ' ' );
   9.258 +	}
   9.259 +
   9.260 +	try
   9.261 +	{
   9.262 +		ObjectCode::Instance().Assemble2( GetOpcode( instructionIndex, mode ), value );
   9.263 +	}
   9.264 +	catch ( AsmException_AssembleError& e )
   9.265 +	{
   9.266 +		e.SetString( m_line );
   9.267 +		e.SetColumn( m_column );
   9.268 +		throw;
   9.269 +	}
   9.270 +}
   9.271 +
   9.272 +
   9.273 +
   9.274 +/*************************************************************************************************/
   9.275 +/**
   9.276 +	LineParser::Assemble3()
   9.277 +*/
   9.278 +/*************************************************************************************************/
   9.279 +void LineParser::Assemble3( int instructionIndex, ADDRESSING_MODE mode, unsigned int value )
   9.280 +{
   9.281 +	assert( value < 0x10000 );
   9.282 +	assert( HasAddressingMode( instructionIndex, mode ) );
   9.283 +
   9.284 +	if ( GlobalData::Instance().ShouldOutputAsm() )
   9.285 +	{
   9.286 +		cout << uppercase << hex << setfill( '0' ) << "     ";
   9.287 +		cout << setw(4) << ObjectCode::Instance().GetPC() << "   ";
   9.288 +		cout << setw(2) << GetOpcode( instructionIndex, mode ) << " ";
   9.289 +		cout << setw(2) << ( value & 0xFF ) << " ";
   9.290 +		cout << setw(2) << ( ( value >> 8 ) & 0xFF ) << "   ";
   9.291 +		cout << m_gaOpcodeTable[ instructionIndex ].m_pName << " ";
   9.292 +
   9.293 +		if ( mode == IND16 )
   9.294 +		{
   9.295 +			cout << "(";
   9.296 +		}
   9.297 +
   9.298 +		cout << "&" << setw(4) << value;
   9.299 +
   9.300 +		if ( mode == ABSX )
   9.301 +		{
   9.302 +			cout << ",X";
   9.303 +		}
   9.304 +		else if ( mode == ABSY )
   9.305 +		{
   9.306 +			cout << ",Y";
   9.307 +		}
   9.308 +		else if ( mode == IND16 )
   9.309 +		{
   9.310 +			cout << ")";
   9.311 +		}
   9.312 +
   9.313 +		cout << endl << nouppercase << dec << setfill( ' ' );
   9.314 +	}
   9.315 +
   9.316 +	try
   9.317 +	{
   9.318 +		ObjectCode::Instance().Assemble3( GetOpcode( instructionIndex, mode ), value );
   9.319 +	}
   9.320 +	catch ( AsmException_AssembleError& e )
   9.321 +	{
   9.322 +		e.SetString( m_line );
   9.323 +		e.SetColumn( m_column );
   9.324 +		throw;
   9.325 +	}
   9.326 +}
   9.327 +
   9.328 +
   9.329 +
   9.330 +/*************************************************************************************************/
   9.331 +/**
   9.332 +	LineParser::HandleAssembler()
   9.333 +*/
   9.334 +/*************************************************************************************************/
   9.335 +void LineParser::HandleAssembler( int instruction )
   9.336 +{
   9.337 +	int oldColumn = m_column;
   9.338 +
   9.339 +	if ( !AdvanceAndCheckEndOfStatement() )
   9.340 +	{
   9.341 +		// there is nothing following the opcode - maybe implied mode... see if this is allowed!
   9.342 +
   9.343 +		if ( HasAddressingMode( instruction, IMP ) )
   9.344 +		{
   9.345 +			// It's allowed - assemble this instruction
   9.346 +			Assemble1( instruction, IMP );
   9.347 +			return;
   9.348 +		}
   9.349 +		else
   9.350 +		{
   9.351 +			// Implied addressing mode not allowed
   9.352 +			throw AsmException_SyntaxError_NoImplied( m_line, oldColumn );
   9.353 +		}
   9.354 +	}
   9.355 +
   9.356 +	// OK, something follows... maybe it's immediate mode
   9.357 +
   9.358 +	if ( m_line[ m_column ] == '#' )
   9.359 +	{
   9.360 +		if ( !HasAddressingMode( instruction, IMM ) )
   9.361 +		{
   9.362 +			// Immediate addressing mode not allowed
   9.363 +			throw AsmException_SyntaxError_NoImmediate( m_line, m_column );
   9.364 +		}
   9.365 +
   9.366 +		m_column++;
   9.367 +		oldColumn = m_column;
   9.368 +
   9.369 +		int value;
   9.370 +
   9.371 +		try
   9.372 +		{
   9.373 +			value = EvaluateExpressionAsInt();
   9.374 +		}
   9.375 +		catch ( AsmException_SyntaxError_SymbolNotDefined& e )
   9.376 +		{
   9.377 +			if ( GlobalData::Instance().IsFirstPass() )
   9.378 +			{
   9.379 +				value = 0;
   9.380 +			}
   9.381 +			else
   9.382 +			{
   9.383 +				throw;
   9.384 +			}
   9.385 +		}
   9.386 +
   9.387 +		if ( value > 0xFF )
   9.388 +		{
   9.389 +			// Immediate constant too large
   9.390 +			throw AsmException_SyntaxError_ImmTooLarge( m_line, oldColumn );
   9.391 +		}
   9.392 +
   9.393 +		if ( value < 0 )
   9.394 +		{
   9.395 +			// Immediate constant is negative
   9.396 +			throw AsmException_SyntaxError_ImmNegative( m_line, oldColumn );
   9.397 +		}
   9.398 +
   9.399 +		if ( m_line[ m_column ] == ',' )
   9.400 +		{
   9.401 +			// Unexpected comma (remembering that an expression can validly end with a comma)
   9.402 +			throw AsmException_SyntaxError_UnexpectedComma( m_line, m_column );
   9.403 +		}
   9.404 +
   9.405 +		// Actually assemble the instruction
   9.406 +		Assemble2( instruction, IMM, static_cast< unsigned int >( value ) );
   9.407 +		return;
   9.408 +	}
   9.409 +
   9.410 +	// see if it's accumulator mode
   9.411 +
   9.412 +	if ( toupper( m_line[ m_column ] ) == 'A' && HasAddressingMode( instruction, ACC ) )
   9.413 +	{
   9.414 +		// might be... but only if the next character is a separator or whitespace
   9.415 +		// otherwise, we must assume a label beginning with A
   9.416 +
   9.417 +		int rememberColumn = m_column;
   9.418 +
   9.419 +		m_column++;
   9.420 +
   9.421 +		if ( !AdvanceAndCheckEndOfStatement() )
   9.422 +		{
   9.423 +			// It is definitely accumulator mode - assemble this instruction
   9.424 +			Assemble1( instruction, ACC );
   9.425 +			return;
   9.426 +		}
   9.427 +		else
   9.428 +		{
   9.429 +			// No - restore pointer so we can consider 'A' as the start of a label name later
   9.430 +			m_column = rememberColumn;
   9.431 +		}
   9.432 +	}
   9.433 +
   9.434 +	// see if it's (ind,X), (ind),Y or (ind16)
   9.435 +
   9.436 +	if ( m_line[ m_column ] == '(' )
   9.437 +	{
   9.438 +		oldColumn = m_column;
   9.439 +		m_column++;
   9.440 +
   9.441 +		int value;
   9.442 +
   9.443 +		try
   9.444 +		{
   9.445 +			// passing true to EvaluateExpression is a hack which allows us to terminate the expression by
   9.446 +			// an extra close bracket.
   9.447 +			value = EvaluateExpressionAsInt( true );
   9.448 +		}
   9.449 +		catch ( AsmException_SyntaxError_SymbolNotDefined& e )
   9.450 +		{
   9.451 +			if ( GlobalData::Instance().IsFirstPass() )
   9.452 +			{
   9.453 +				value = 0;
   9.454 +			}
   9.455 +			else
   9.456 +			{
   9.457 +				throw;
   9.458 +			}
   9.459 +		}
   9.460 +
   9.461 +		// the only valid character to find here is ',' for (ind,X) and ')' for (ind),Y and (ind16)
   9.462 +
   9.463 +		// check (ind16) and (ind),Y
   9.464 +
   9.465 +		if ( m_line[ m_column ] == ')' )
   9.466 +		{
   9.467 +			m_column++;
   9.468 +
   9.469 +			// check (ind16)
   9.470 +
   9.471 +			if ( !AdvanceAndCheckEndOfStatement() )
   9.472 +			{
   9.473 +				// nothing else here - must be ind16... see if this is allowed!
   9.474 +
   9.475 +				if ( !HasAddressingMode( instruction, IND16 ) )
   9.476 +				{
   9.477 +					throw AsmException_SyntaxError_NoIndirect16( m_line, oldColumn );
   9.478 +				}
   9.479 +
   9.480 +				// It is definitely ind16 mode - check for the 6502 bug
   9.481 +
   9.482 +				if ( ( value & 0xFF ) == 0xFF )
   9.483 +				{
   9.484 +					// victim of the 6502 bug!  throw an error
   9.485 +					throw AsmException_SyntaxError_6502Bug( m_line, oldColumn + 1 );
   9.486 +				}
   9.487 +
   9.488 +				Assemble3( instruction, IND16, value );
   9.489 +				return;
   9.490 +			}
   9.491 +
   9.492 +			// if we find ,Y then it's an (ind),Y
   9.493 +
   9.494 +			if ( m_line[ m_column ] == ',' )
   9.495 +			{
   9.496 +				m_column++;
   9.497 +
   9.498 +				if ( !AdvanceAndCheckEndOfStatement() )
   9.499 +				{
   9.500 +					// We expected more characters but there were none
   9.501 +					throw AsmException_SyntaxError_BadIndirect( m_line, m_column );
   9.502 +				}
   9.503 +
   9.504 +				if ( toupper( m_line[ m_column ] ) != 'Y' )
   9.505 +				{
   9.506 +					// We were expecting an Y
   9.507 +					throw AsmException_SyntaxError_BadIndirect( m_line, m_column );
   9.508 +				}
   9.509 +
   9.510 +				m_column++;
   9.511 +
   9.512 +				if ( AdvanceAndCheckEndOfStatement() )
   9.513 +				{
   9.514 +					// We were not expecting any more characters
   9.515 +					throw AsmException_SyntaxError_BadIndirect( m_line, m_column );
   9.516 +				}
   9.517 +
   9.518 +				// It is definitely (ind),Y - check we can use it
   9.519 +
   9.520 +				if ( !HasAddressingMode( instruction, INDY ) )
   9.521 +				{
   9.522 +					// addressing mode not allowed
   9.523 +					throw AsmException_SyntaxError_NoIndirect( m_line, oldColumn );
   9.524 +				}
   9.525 +
   9.526 +				// assemble (ind),Y instruction
   9.527 +
   9.528 +				if ( value > 0xFF )
   9.529 +				{
   9.530 +					// it's not ZP and it must be
   9.531 +					throw AsmException_SyntaxError_NotZeroPage( m_line, oldColumn + 1 );
   9.532 +				}
   9.533 +
   9.534 +				Assemble2( instruction, INDY, value );
   9.535 +				return;
   9.536 +			}
   9.537 +
   9.538 +			// If we got here, we identified neither (ind16) nor (ind),Y
   9.539 +			// Therefore we throw a syntax error
   9.540 +
   9.541 +			throw AsmException_SyntaxError_BadIndirect( m_line, m_column );
   9.542 +		}
   9.543 +
   9.544 +		// check (ind,X)
   9.545 +
   9.546 +		if ( m_line[ m_column ] == ',' )
   9.547 +		{
   9.548 +			m_column++;
   9.549 +
   9.550 +			if ( !AdvanceAndCheckEndOfStatement() )
   9.551 +			{
   9.552 +				// We expected more characters but there were none
   9.553 +				throw AsmException_SyntaxError_BadIndirect( m_line, m_column );
   9.554 +			}
   9.555 +
   9.556 +			if ( toupper( m_line[ m_column ] ) != 'X' )
   9.557 +			{
   9.558 +				// We were expecting an X
   9.559 +				throw AsmException_SyntaxError_BadIndirect( m_line, m_column );
   9.560 +			}
   9.561 +
   9.562 +			m_column++;
   9.563 +
   9.564 +			if ( !AdvanceAndCheckEndOfStatement() )
   9.565 +			{
   9.566 +				// We expected more characters but there were none
   9.567 +				throw AsmException_SyntaxError_MismatchedParentheses( m_line, m_column );
   9.568 +			}
   9.569 +
   9.570 +			if ( m_line[ m_column ] != ')' )
   9.571 +			{
   9.572 +				// We were expecting a close bracket
   9.573 +				throw AsmException_SyntaxError_MismatchedParentheses( m_line, m_column );
   9.574 +			}
   9.575 +
   9.576 +			m_column++;
   9.577 +
   9.578 +			if ( AdvanceAndCheckEndOfStatement() )
   9.579 +			{
   9.580 +				// We were not expecting any more characters
   9.581 +				throw AsmException_SyntaxError_BadIndirect( m_line, m_column );
   9.582 +			}
   9.583 +
   9.584 +			// It is definitely (ind,X) - check we can use it
   9.585 +
   9.586 +			if ( !HasAddressingMode( instruction, INDX ) )
   9.587 +			{
   9.588 +				// addressing mode not allowed
   9.589 +				throw AsmException_SyntaxError_NoIndirect( m_line, oldColumn );
   9.590 +			}
   9.591 +
   9.592 +			// It is definitely (ind,X) - assemble this instruction
   9.593 +
   9.594 +			if ( value > 0xFF )
   9.595 +			{
   9.596 +				// it's not ZP and it must be
   9.597 +				throw AsmException_SyntaxError_NotZeroPage( m_line, oldColumn + 1 );
   9.598 +			}
   9.599 +
   9.600 +			Assemble2( instruction, INDX, value );
   9.601 +			return;
   9.602 +		}
   9.603 +
   9.604 +		// If we got here, we identified neither (ind16), (ind,X) nor (ind),Y
   9.605 +		// Therefore we throw a syntax error
   9.606 +
   9.607 +		throw AsmException_SyntaxError_BadIndirect( m_line, m_column );
   9.608 +	}
   9.609 +
   9.610 +	// if we got here, it must be abs abs,X abs,Y zp zp,X or zp,Y
   9.611 +	// we give priority to trying to match zp as they are the preference
   9.612 +
   9.613 +	// get the address operand
   9.614 +
   9.615 +	oldColumn = m_column;
   9.616 +	int value;
   9.617 +
   9.618 +	try
   9.619 +	{
   9.620 +		value = EvaluateExpressionAsInt();
   9.621 +	}
   9.622 +	catch ( AsmException_SyntaxError_SymbolNotDefined& e )
   9.623 +	{
   9.624 +		if ( GlobalData::Instance().IsFirstPass() )
   9.625 +		{
   9.626 +			// this allows branches to assemble when the value is unknown due to a label not having
   9.627 +			// yet been defined.  Also, this is most likely a 16-bit value, which is a sensible
   9.628 +			// default addressing mode to assume.
   9.629 +			value = ObjectCode::Instance().GetPC();
   9.630 +		}
   9.631 +		else
   9.632 +		{
   9.633 +			throw;
   9.634 +		}
   9.635 +	}
   9.636 +
   9.637 +	if ( !AdvanceAndCheckEndOfStatement() )
   9.638 +	{
   9.639 +		// end of this instruction
   9.640 +
   9.641 +		// see if this is relative addressing (branch)
   9.642 +
   9.643 +		if ( HasAddressingMode( instruction, REL ) )
   9.644 +		{
   9.645 +			int branchAmount = value - ( ObjectCode::Instance().GetPC() + 2 );
   9.646 +
   9.647 +			if ( branchAmount >= -128 && branchAmount <= 127 )
   9.648 +			{
   9.649 +				Assemble2( instruction, REL, branchAmount & 0xFF );
   9.650 +				return;
   9.651 +			}
   9.652 +			else
   9.653 +			{
   9.654 +				throw AsmException_SyntaxError_BranchOutOfRange( m_line, oldColumn );
   9.655 +			}
   9.656 +		}
   9.657 +
   9.658 +		// else this must be abs or zp
   9.659 +		// we assemble abs or zp depending on whether 'value' is a 16- or 8-bit number.
   9.660 +		// we contrive that unknown labels will get a 16-bit value so that absolute addressing is the default.
   9.661 +
   9.662 +		if ( value < 0x100 && HasAddressingMode( instruction, ZP ) )
   9.663 +		{
   9.664 +			Assemble2( instruction, ZP, value );
   9.665 +			return;
   9.666 +		}
   9.667 +		else if ( HasAddressingMode( instruction, ABS ) )
   9.668 +		{
   9.669 +			Assemble3( instruction, ABS, value );
   9.670 +			return;
   9.671 +		}
   9.672 +		else
   9.673 +		{
   9.674 +			throw AsmException_SyntaxError_NoAbsolute( m_line, oldColumn );
   9.675 +		}
   9.676 +	}
   9.677 +
   9.678 +	// finally, check for indexed versions of the opcode
   9.679 +
   9.680 +	if ( m_line[ m_column ] != ',' )
   9.681 +	{
   9.682 +		// weird character - throw error
   9.683 +		throw AsmException_SyntaxError_BadAbsolute( m_line, m_column );
   9.684 +	}
   9.685 +
   9.686 +	m_column++;
   9.687 +
   9.688 +	if ( !AdvanceAndCheckEndOfStatement() )
   9.689 +	{
   9.690 +		// We expected more characters but there were none
   9.691 +		throw AsmException_SyntaxError_BadAbsolute( m_line, m_column );
   9.692 +	}
   9.693 +
   9.694 +	if ( toupper( m_line[ m_column ] == 'X' ) )
   9.695 +	{
   9.696 +		m_column++;
   9.697 +
   9.698 +		if ( AdvanceAndCheckEndOfStatement() )
   9.699 +		{
   9.700 +			// We were not expecting any more characters
   9.701 +			throw AsmException_SyntaxError_BadIndexed( m_line, m_column );
   9.702 +		}
   9.703 +
   9.704 +		if ( value < 0x100 && HasAddressingMode( instruction, ZPX ) )
   9.705 +		{
   9.706 +			Assemble2( instruction, ZPX, value );
   9.707 +			return;
   9.708 +		}
   9.709 +		else if ( HasAddressingMode( instruction, ABSX ) )
   9.710 +		{
   9.711 +			Assemble3( instruction, ABSX, value );
   9.712 +			return;
   9.713 +		}
   9.714 +		else
   9.715 +		{
   9.716 +			throw AsmException_SyntaxError_NoIndexedX( m_line, oldColumn );
   9.717 +		}
   9.718 +	}
   9.719 +
   9.720 +	if ( toupper( m_line[ m_column ] == 'Y' ) )
   9.721 +	{
   9.722 +		m_column++;
   9.723 +
   9.724 +		if ( AdvanceAndCheckEndOfStatement() )
   9.725 +		{
   9.726 +			// We were not expecting any more characters
   9.727 +			throw AsmException_SyntaxError_BadIndexed( m_line, m_column );
   9.728 +		}
   9.729 +
   9.730 +		if ( value < 0x100 && HasAddressingMode( instruction, ZPY ) )
   9.731 +		{
   9.732 +			Assemble2( instruction, ZPY, value );
   9.733 +			return;
   9.734 +		}
   9.735 +		else if ( HasAddressingMode( instruction, ABSY ) )
   9.736 +		{
   9.737 +			Assemble3( instruction, ABSY, value );
   9.738 +			return;
   9.739 +		}
   9.740 +		else
   9.741 +		{
   9.742 +			throw AsmException_SyntaxError_NoIndexedY( m_line, oldColumn );
   9.743 +		}
   9.744 +	}
   9.745 +
   9.746 +	// If we got here, we received a weird index, like LDA addr,Z
   9.747 +
   9.748 +	throw AsmException_SyntaxError_BadIndexed( m_line, m_column );
   9.749 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/commands.cpp	Sat May 01 19:35:42 2010 +0100
    10.3 @@ -0,0 +1,1051 @@
    10.4 +/*************************************************************************************************/
    10.5 +/**
    10.6 +	commands.cpp
    10.7 +
    10.8 +	Contains all the LineParser methods for parsing and handling assembler commands
    10.9 +*/
   10.10 +/*************************************************************************************************/
   10.11 +
   10.12 +#include <iostream>
   10.13 +#include <iomanip>
   10.14 +#include <string>
   10.15 +
   10.16 +#include "lineparser.h"
   10.17 +#include "globaldata.h"
   10.18 +#include "objectcode.h"
   10.19 +#include "symboltable.h"
   10.20 +#include "sourcefile.h"
   10.21 +#include "asmexception.h"
   10.22 +#include "discimage.h"
   10.23 +
   10.24 +
   10.25 +using namespace std;
   10.26 +
   10.27 +
   10.28 +LineParser::Token	LineParser::m_gaTokenTable[] =
   10.29 +{
   10.30 +	{ ".",			&LineParser::HandleDefineLabel },
   10.31 +	{ "\\",			&LineParser::HandleDefineComment },
   10.32 +	{ ";",			&LineParser::HandleDefineComment },
   10.33 +	{ ":",			&LineParser::HandleStatementSeparator },
   10.34 +	{ "PRINT",		&LineParser::HandlePrint },
   10.35 +	{ "ORG",		&LineParser::HandleOrg },
   10.36 +	{ "INCLUDE",	&LineParser::HandleInclude },
   10.37 +	{ "EQUB",		&LineParser::HandleEqub },
   10.38 +	{ "EQUS",		&LineParser::HandleEqub },
   10.39 +	{ "EQUW",		&LineParser::HandleEquw },
   10.40 +	{ "SAVE",		&LineParser::HandleSave },
   10.41 +	{ "FOR",		&LineParser::HandleFor },
   10.42 +	{ "NEXT",		&LineParser::HandleNext },
   10.43 +	{ "IF",			&LineParser::HandleIf },
   10.44 +	{ "ELSE",		&LineParser::HandleElse },
   10.45 +	{ "ENDIF",		&LineParser::HandleEndif },
   10.46 +	{ "ALIGN",		&LineParser::HandleAlign },
   10.47 +	{ "SKIP",		&LineParser::HandleSkip },
   10.48 +	{ "GUARD",		&LineParser::HandleGuard },
   10.49 +	{ "CLEAR",		&LineParser::HandleClear }
   10.50 +};
   10.51 +
   10.52 +
   10.53 +
   10.54 +
   10.55 +/*************************************************************************************************/
   10.56 +/**
   10.57 +	LineParser::GetTokenAndAdvanceColumn()
   10.58 +
   10.59 +	Searches for a token match in the current line, starting at the current column,
   10.60 +	and moves the column pointer past the token
   10.61 +
   10.62 +	@param		line			The string to parse
   10.63 +	@param		column			The column to start from
   10.64 +
   10.65 +	@return		The token number, or -1 for "not found"
   10.66 +				column is modified to index the character after the token
   10.67 +*/
   10.68 +/*************************************************************************************************/
   10.69 +int LineParser::GetTokenAndAdvanceColumn()
   10.70 +{
   10.71 +	for ( int i = 0; i < static_cast<int>( sizeof m_gaTokenTable / sizeof( Token ) ); i++ )
   10.72 +	{
   10.73 +		const char*	token	= m_gaTokenTable[ i ].m_pName;
   10.74 +		size_t		len		= strlen( token );
   10.75 +
   10.76 +		// create lower-case version of token
   10.77 +
   10.78 +		char tokenLC[ 16 ];
   10.79 +
   10.80 +		for ( size_t j = 0; j <= len; j++ )
   10.81 +		{
   10.82 +			tokenLC[ j ] = tolower( token[ j ] );
   10.83 +		}
   10.84 +
   10.85 +		// see if token matches
   10.86 +
   10.87 +		if ( m_line.compare( m_column, len, token ) == 0 ||
   10.88 +			 m_line.compare( m_column, len, tokenLC ) == 0 )
   10.89 +		{
   10.90 +			m_column += len;
   10.91 +			return i;
   10.92 +		}
   10.93 +	}
   10.94 +
   10.95 +	return -1;
   10.96 +}
   10.97 +
   10.98 +
   10.99 +
  10.100 +/*************************************************************************************************/
  10.101 +/**
  10.102 +	LineParser::HandleDefineLabel()
  10.103 +*/
  10.104 +/*************************************************************************************************/
  10.105 +void LineParser::HandleDefineLabel()
  10.106 +{
  10.107 +	if ( isalpha( m_line[ m_column ] ) || m_line[ m_column ] == '_' )
  10.108 +	{
  10.109 +		// Symbol starts with a valid character
  10.110 +
  10.111 +		int oldColumn = m_column;
  10.112 +
  10.113 +		// Get the symbol name
  10.114 +
  10.115 +		string symbolName = GetSymbolName();
  10.116 +
  10.117 +		// ...and mangle it according to whether we are in a FOR loop
  10.118 +
  10.119 +		string fullSymbolName = symbolName + m_sourceFile->GetSymbolNameSuffix();
  10.120 +
  10.121 +		if ( GlobalData::Instance().IsFirstPass() )
  10.122 +		{
  10.123 +			// only add the symbol on the first pass
  10.124 +
  10.125 +			if ( SymbolTable::Instance().IsSymbolDefined( fullSymbolName ) )
  10.126 +			{
  10.127 +				throw AsmException_SyntaxError_LabelAlreadyDefined( m_line, oldColumn );
  10.128 +			}
  10.129 +			else
  10.130 +			{
  10.131 +				SymbolTable::Instance().AddSymbol( fullSymbolName, ObjectCode::Instance().GetPC() );
  10.132 +			}
  10.133 +		}
  10.134 +		else
  10.135 +		{
  10.136 +			// on the second pass, check that the label would be assigned the same value
  10.137 +
  10.138 +			if ( SymbolTable::Instance().GetSymbol( fullSymbolName ) != ObjectCode::Instance().GetPC() )
  10.139 +			{
  10.140 +				throw AsmException_SyntaxError_SecondPassProblem( m_line, oldColumn );
  10.141 +			}
  10.142 +		}
  10.143 +
  10.144 +		if ( GlobalData::Instance().ShouldOutputAsm() )
  10.145 +		{
  10.146 +			cout << "." << symbolName << endl;
  10.147 +		}
  10.148 +	}
  10.149 +	else
  10.150 +	{
  10.151 +		throw AsmException_SyntaxError_InvalidSymbolName( m_line, m_column );
  10.152 +	}
  10.153 +}
  10.154 +
  10.155 +
  10.156 +
  10.157 +/*************************************************************************************************/
  10.158 +/**
  10.159 +	LineParser::HandleDefineComment()
  10.160 +*/
  10.161 +/*************************************************************************************************/
  10.162 +void LineParser::HandleDefineComment()
  10.163 +{
  10.164 +	// skip rest of line
  10.165 +	m_column = m_line.length();
  10.166 +}
  10.167 +
  10.168 +
  10.169 +
  10.170 +/*************************************************************************************************/
  10.171 +/**
  10.172 +	LineParser::HandleStatementSeparator()
  10.173 +*/
  10.174 +/*************************************************************************************************/
  10.175 +void LineParser::HandleStatementSeparator()
  10.176 +{
  10.177 +	// do nothing!
  10.178 +}
  10.179 +
  10.180 +
  10.181 +
  10.182 +/*************************************************************************************************/
  10.183 +/**
  10.184 +	LineParser::HandleOrg()
  10.185 +*/
  10.186 +/*************************************************************************************************/
  10.187 +void LineParser::HandleOrg()
  10.188 +{
  10.189 +	int newPC = EvaluateExpressionAsInt();
  10.190 +	if ( newPC < 0 || newPC > 0xFFFF )
  10.191 +	{
  10.192 +		throw AsmException_SyntaxError_OutOfRange( m_line, m_column );
  10.193 +	}
  10.194 +
  10.195 +	ObjectCode::Instance().SetPC( newPC );
  10.196 +	SymbolTable::Instance().ChangeSymbol( "P%", newPC );
  10.197 +
  10.198 +	if ( m_line[ m_column ] == ',' )
  10.199 +	{
  10.200 +		// Unexpected comma (remembering that an expression can validly end with a comma)
  10.201 +		throw AsmException_SyntaxError_UnexpectedComma( m_line, m_column );
  10.202 +	}
  10.203 +}
  10.204 +
  10.205 +
  10.206 +
  10.207 +/*************************************************************************************************/
  10.208 +/**
  10.209 +	LineParser::HandleGuard()
  10.210 +*/
  10.211 +/*************************************************************************************************/
  10.212 +void LineParser::HandleGuard()
  10.213 +{
  10.214 +	int val = EvaluateExpressionAsInt();
  10.215 +	if ( val < 0 || val > 0xFFFF )
  10.216 +	{
  10.217 +		throw AsmException_SyntaxError_OutOfRange( m_line, m_column );
  10.218 +	}
  10.219 +
  10.220 +	ObjectCode::Instance().SetGuard( val );
  10.221 +
  10.222 +	if ( m_line[ m_column ] == ',' )
  10.223 +	{
  10.224 +		// Unexpected comma (remembering that an expression can validly end with a comma)
  10.225 +		throw AsmException_SyntaxError_UnexpectedComma( m_line, m_column );
  10.226 +	}
  10.227 +}
  10.228 +
  10.229 +
  10.230 +
  10.231 +/*************************************************************************************************/
  10.232 +/**
  10.233 +	LineParser::HandleClear()
  10.234 +*/
  10.235 +/*************************************************************************************************/
  10.236 +void LineParser::HandleClear()
  10.237 +{
  10.238 +	int start = EvaluateExpressionAsInt();
  10.239 +	if ( start < 0 || start > 0xFFFF )
  10.240 +	{
  10.241 +		throw AsmException_SyntaxError_OutOfRange( m_line, m_column );
  10.242 +	}
  10.243 +
  10.244 +	if ( m_line[ m_column ] != ',' )
  10.245 +	{
  10.246 +		// did not find a comma
  10.247 +		throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column );
  10.248 +	}
  10.249 +
  10.250 +	m_column++;
  10.251 +
  10.252 +	int end = EvaluateExpressionAsInt();
  10.253 +	if ( end < 0 || end > 0xFFFF )
  10.254 +	{
  10.255 +		throw AsmException_SyntaxError_OutOfRange( m_line, m_column );
  10.256 +	}
  10.257 +
  10.258 +	ObjectCode::Instance().Clear( start, end );
  10.259 +
  10.260 +	if ( m_line[ m_column ] == ',' )
  10.261 +	{
  10.262 +		// Unexpected comma (remembering that an expression can validly end with a comma)
  10.263 +		throw AsmException_SyntaxError_UnexpectedComma( m_line, m_column );
  10.264 +	}
  10.265 +}
  10.266 +
  10.267 +
  10.268 +
  10.269 +/*************************************************************************************************/
  10.270 +/**
  10.271 +	LineParser::HandleAlign()
  10.272 +*/
  10.273 +/*************************************************************************************************/
  10.274 +void LineParser::HandleAlign()
  10.275 +{
  10.276 +	int oldColumn = m_column;
  10.277 +
  10.278 +	int val = EvaluateExpressionAsInt();
  10.279 +	if ( val < 1 || ( val & ( val - 1 ) ) != 0 )
  10.280 +	{
  10.281 +		throw AsmException_SyntaxError_BadAlignment( m_line, oldColumn );
  10.282 +	}
  10.283 +
  10.284 +	while ( ( ObjectCode::Instance().GetPC() & ( val - 1 ) ) != 0 )
  10.285 +	{
  10.286 +		try
  10.287 +		{
  10.288 +			ObjectCode::Instance().PutByte( 0 );
  10.289 +		}
  10.290 +		catch ( AsmException_AssembleError& e )
  10.291 +		{
  10.292 +			e.SetString( m_line );
  10.293 +			e.SetColumn( m_column );
  10.294 +			throw;
  10.295 +		}
  10.296 +	}
  10.297 +
  10.298 +	if ( m_line[ m_column ] == ',' )
  10.299 +	{
  10.300 +		// Unexpected comma (remembering that an expression can validly end with a comma)
  10.301 +		throw AsmException_SyntaxError_UnexpectedComma( m_line, m_column );
  10.302 +	}
  10.303 +}
  10.304 +
  10.305 +
  10.306 +
  10.307 +/*************************************************************************************************/
  10.308 +/**
  10.309 +	LineParser::HandleSkip()
  10.310 +*/
  10.311 +/*************************************************************************************************/
  10.312 +void LineParser::HandleSkip()
  10.313 +{
  10.314 +	int oldColumn = m_column;
  10.315 +
  10.316 +	int val = EvaluateExpressionAsInt();
  10.317 +	if ( val < 0 )
  10.318 +	{
  10.319 +		throw AsmException_SyntaxError_ImmNegative( m_line, oldColumn );
  10.320 +	}
  10.321 +
  10.322 +	for ( int i = 0; i < val; i++ )
  10.323 +	{
  10.324 +		try
  10.325 +		{
  10.326 +			ObjectCode::Instance().PutByte( 0 );
  10.327 +		}
  10.328 +		catch ( AsmException_AssembleError& e )
  10.329 +		{
  10.330 +			e.SetString( m_line );
  10.331 +			e.SetColumn( m_column );
  10.332 +			throw;
  10.333 +		}
  10.334 +	}
  10.335 +
  10.336 +	if ( m_line[ m_column ] == ',' )
  10.337 +	{
  10.338 +		// Unexpected comma (remembering that an expression can validly end with a comma)
  10.339 +		throw AsmException_SyntaxError_UnexpectedComma( m_line, m_column );
  10.340 +	}
  10.341 +}
  10.342 +
  10.343 +
  10.344 +
  10.345 +/*************************************************************************************************/
  10.346 +/**
  10.347 +	LineParser::HandleInclude()
  10.348 +*/
  10.349 +/*************************************************************************************************/
  10.350 +void LineParser::HandleInclude()
  10.351 +{
  10.352 +	if ( m_sourceFile->GetForLevel() > 0 )
  10.353 +	{
  10.354 +		// disallow an include within a FOR loop
  10.355 +		throw AsmException_SyntaxError_CantInclude( m_line, m_column );
  10.356 +	}
  10.357 +
  10.358 +	if ( !AdvanceAndCheckEndOfStatement() )
  10.359 +	{
  10.360 +		throw AsmException_SyntaxError_EmptyExpression( m_line, m_column );
  10.361 +	}
  10.362 +
  10.363 +	if ( m_line[ m_column ] != '\"' )
  10.364 +	{
  10.365 +		throw AsmException_SyntaxError_EmptyExpression( m_line, m_column );
  10.366 +	}
  10.367 +
  10.368 +	// string
  10.369 +	size_t endQuotePos = m_line.find_first_of( '\"', m_column + 1 );
  10.370 +
  10.371 +	if ( endQuotePos == string::npos )
  10.372 +	{
  10.373 +		throw AsmException_SyntaxError_MissingQuote( m_line, m_line.length() );
  10.374 +	}
  10.375 +	else
  10.376 +	{
  10.377 +		string filename( m_line.substr( m_column + 1, endQuotePos - m_column - 1 ) );
  10.378 +
  10.379 +		if ( GlobalData::Instance().IsFirstPass() )
  10.380 +		{
  10.381 +			cout << "Including file " << filename << endl;
  10.382 +		}
  10.383 +
  10.384 +		SourceFile input( filename.c_str() );
  10.385 +		input.Process();
  10.386 +	}
  10.387 +
  10.388 +	m_column = endQuotePos + 1;
  10.389 +
  10.390 +	if ( AdvanceAndCheckEndOfStatement() )
  10.391 +	{
  10.392 +		throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column );
  10.393 +	}
  10.394 +}
  10.395 +
  10.396 +
  10.397 +
  10.398 +/*************************************************************************************************/
  10.399 +/**
  10.400 +	LineParser::HandleEqub()
  10.401 +*/
  10.402 +/*************************************************************************************************/
  10.403 +void LineParser::HandleEqub()
  10.404 +{
  10.405 +	do
  10.406 +	{
  10.407 +		if ( !AdvanceAndCheckEndOfStatement() )
  10.408 +		{
  10.409 +			throw AsmException_SyntaxError_EmptyExpression( m_line, m_column );
  10.410 +		}
  10.411 +
  10.412 +		// handle string
  10.413 +
  10.414 +		if ( m_line[ m_column ] == '\"' )
  10.415 +		{
  10.416 +			size_t endQuotePos = m_line.find_first_of( '\"', m_column + 1 );
  10.417 +
  10.418 +			if ( endQuotePos == string::npos )
  10.419 +			{
  10.420 +				throw AsmException_SyntaxError_MissingQuote( m_line, m_line.length() );
  10.421 +			}
  10.422 +			else
  10.423 +			{
  10.424 +				string equs( m_line.substr( m_column + 1, endQuotePos - m_column - 1 ) );
  10.425 +
  10.426 +				if ( GlobalData::Instance().ShouldOutputAsm() )
  10.427 +				{
  10.428 +					cout << uppercase << hex << setfill( '0' ) << "     ";
  10.429 +					cout << setw(4) << ObjectCode::Instance().GetPC() << "   ";
  10.430 +				}
  10.431 +
  10.432 +				for ( size_t i = 0; i < equs.length(); i++ )
  10.433 +				{
  10.434 +					if ( GlobalData::Instance().ShouldOutputAsm() )
  10.435 +					{
  10.436 +						if ( i < 3 )
  10.437 +						{
  10.438 +							cout << setw(2) << static_cast< int >( equs[ i ] ) << " ";
  10.439 +						}
  10.440 +						else if ( i == 3 )
  10.441 +						{
  10.442 +							cout << "...";
  10.443 +						}
  10.444 +					}
  10.445 +
  10.446 +					try
  10.447 +					{
  10.448 +						ObjectCode::Instance().PutByte( equs[ i ] );
  10.449 +					}
  10.450 +					catch ( AsmException_AssembleError& e )
  10.451 +					{
  10.452 +						e.SetString( m_line );
  10.453 +						e.SetColumn( m_column );
  10.454 +						throw;
  10.455 +					}
  10.456 +				}
  10.457 +
  10.458 +				if ( GlobalData::Instance().ShouldOutputAsm() )
  10.459 +				{
  10.460 +					cout << endl << nouppercase << dec << setfill( ' ' );
  10.461 +				}
  10.462 +			}
  10.463 +
  10.464 +			m_column = endQuotePos + 1;
  10.465 +		}
  10.466 +		else
  10.467 +		{
  10.468 +			// handle byte
  10.469 +
  10.470 +			int value;
  10.471 +
  10.472 +			try
  10.473 +			{
  10.474 +				value = EvaluateExpressionAsInt();
  10.475 +			}
  10.476 +			catch ( AsmException_SyntaxError_SymbolNotDefined& e )
  10.477 +			{
  10.478 +				if ( GlobalData::Instance().IsFirstPass() )
  10.479 +				{
  10.480 +					value = 0;
  10.481 +				}
  10.482 +				else
  10.483 +				{
  10.484 +					throw;
  10.485 +				}
  10.486 +			}
  10.487 +
  10.488 +			if ( value > 0xFF )
  10.489 +			{
  10.490 +				throw AsmException_SyntaxError_NumberTooBig( m_line, m_column );
  10.491 +			}
  10.492 +
  10.493 +			if ( GlobalData::Instance().ShouldOutputAsm() )
  10.494 +			{
  10.495 +				cout << uppercase << hex << setfill( '0' ) << "     ";
  10.496 +				cout << setw(4) << ObjectCode::Instance().GetPC() << "   ";
  10.497 +				cout << setw(2) << ( value & 0xFF );
  10.498 +				cout << endl << nouppercase << dec << setfill( ' ' );
  10.499 +			}
  10.500 +
  10.501 +			try
  10.502 +			{
  10.503 +				ObjectCode::Instance().PutByte( value & 0xFF );
  10.504 +			}
  10.505 +			catch ( AsmException_AssembleError& e )
  10.506 +			{
  10.507 +				e.SetString( m_line );
  10.508 +				e.SetColumn( m_column );
  10.509 +				throw;
  10.510 +			}
  10.511 +		}
  10.512 +
  10.513 +		if ( !AdvanceAndCheckEndOfStatement() )
  10.514 +		{
  10.515 +			break;
  10.516 +		}
  10.517 +
  10.518 +		if ( m_line[ m_column ] != ',' )
  10.519 +		{
  10.520 +			throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column );
  10.521 +		}
  10.522 +
  10.523 +		m_column++;
  10.524 +
  10.525 +	} while ( true );
  10.526 +}
  10.527 +
  10.528 +
  10.529 +
  10.530 +/*************************************************************************************************/
  10.531 +/**
  10.532 +	LineParser::HandleEquw()
  10.533 +*/
  10.534 +/*************************************************************************************************/
  10.535 +void LineParser::HandleEquw()
  10.536 +{
  10.537 +	do
  10.538 +	{
  10.539 +		int value;
  10.540 +
  10.541 +		try
  10.542 +		{
  10.543 +			value = EvaluateExpressionAsInt();
  10.544 +		}
  10.545 +		catch ( AsmException_SyntaxError_SymbolNotDefined& e )
  10.546 +		{
  10.547 +			if ( GlobalData::Instance().IsFirstPass() )
  10.548 +			{
  10.549 +				value = 0;
  10.550 +			}
  10.551 +			else
  10.552 +			{
  10.553 +				throw;
  10.554 +			}
  10.555 +		}
  10.556 +
  10.557 +		if ( value > 0xFFFF )
  10.558 +		{
  10.559 +			throw AsmException_SyntaxError_NumberTooBig( m_line, m_column );
  10.560 +		}
  10.561 +
  10.562 +		if ( GlobalData::Instance().ShouldOutputAsm() )
  10.563 +		{
  10.564 +			cout << uppercase << hex << setfill( '0' ) << "     ";
  10.565 +			cout << setw(4) << ObjectCode::Instance().GetPC() << "   ";
  10.566 +			cout << setw(2) << ( value & 0xFF ) << " ";
  10.567 +			cout << setw(2) << ( ( value & 0xFF00 ) >> 8 );
  10.568 +			cout << endl << nouppercase << dec << setfill( ' ' );
  10.569 +		}
  10.570 +
  10.571 +		try
  10.572 +		{
  10.573 +			ObjectCode::Instance().PutByte( value & 0xFF );
  10.574 +			ObjectCode::Instance().PutByte( ( value & 0xFF00 ) >> 8 );
  10.575 +		}
  10.576 +		catch ( AsmException_AssembleError& e )
  10.577 +		{
  10.578 +			e.SetString( m_line );
  10.579 +			e.SetColumn( m_column );
  10.580 +			throw;
  10.581 +		}
  10.582 +
  10.583 +		if ( !AdvanceAndCheckEndOfStatement() )
  10.584 +		{
  10.585 +			break;
  10.586 +		}
  10.587 +
  10.588 +		if ( m_line[ m_column ] != ',' )
  10.589 +		{
  10.590 +			throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column );
  10.591 +		}
  10.592 +
  10.593 +		m_column++;
  10.594 +
  10.595 +		if ( !AdvanceAndCheckEndOfStatement() )
  10.596 +		{
  10.597 +			throw AsmException_SyntaxError_EmptyExpression( m_line, m_column );
  10.598 +		}
  10.599 +
  10.600 +	} while ( true );
  10.601 +}
  10.602 +
  10.603 +
  10.604 +
  10.605 +/*************************************************************************************************/
  10.606 +/**
  10.607 +	LineParser::HandleSave()
  10.608 +*/
  10.609 +/*************************************************************************************************/
  10.610 +void LineParser::HandleSave()
  10.611 +{
  10.612 +	int start = 0;
  10.613 +	int end = 0;
  10.614 +	int exec = 0;
  10.615 +
  10.616 +	// syntax is SAVE "filename", start, end [, exec]
  10.617 +
  10.618 +	if ( !AdvanceAndCheckEndOfStatement() )
  10.619 +	{
  10.620 +		// found nothing
  10.621 +		throw AsmException_SyntaxError_EmptyExpression( m_line, m_column );
  10.622 +	}
  10.623 +
  10.624 +	if ( m_line[ m_column ] != '\"' )
  10.625 +	{
  10.626 +		// did not find a string
  10.627 +		throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column );
  10.628 +	}
  10.629 +
  10.630 +	// get filename
  10.631 +
  10.632 +	size_t endQuotePos = m_line.find_first_of( '\"', m_column + 1 );
  10.633 +
  10.634 +	if ( endQuotePos == string::npos )
  10.635 +	{
  10.636 +		// did not find the end of the string
  10.637 +		throw AsmException_SyntaxError_MissingQuote( m_line, m_line.length() );
  10.638 +	}
  10.639 +
  10.640 +	string saveFile( m_line.substr( m_column + 1, endQuotePos - m_column - 1 ) );
  10.641 +
  10.642 +	if ( GlobalData::Instance().ShouldOutputAsm() )
  10.643 +	{
  10.644 +		cout << "Saving file '" << saveFile << "'" << endl;
  10.645 +	}
  10.646 +
  10.647 +	m_column = endQuotePos + 1;
  10.648 +
  10.649 +	// get start address
  10.650 +
  10.651 +	if ( !AdvanceAndCheckEndOfStatement() )
  10.652 +	{
  10.653 +		// found nothing
  10.654 +		throw AsmException_SyntaxError_EmptyExpression( m_line, m_column );
  10.655 +	}
  10.656 +
  10.657 +	if ( m_line[ m_column ] != ',' )
  10.658 +	{
  10.659 +		// did not find a comma
  10.660 +		throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column );
  10.661 +	}
  10.662 +
  10.663 +	m_column++;
  10.664 +
  10.665 +	start = EvaluateExpressionAsInt();
  10.666 +
  10.667 +	if ( start < 0 || start > 0xFFFF )
  10.668 +	{
  10.669 +		throw AsmException_SyntaxError_OutOfRange( m_line, m_column );
  10.670 +	}
  10.671 +
  10.672 +	// get end address
  10.673 +
  10.674 +	if ( m_line[ m_column ] != ',' )
  10.675 +	{
  10.676 +		// did not find a comma
  10.677 +		throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column );
  10.678 +	}
  10.679 +
  10.680 +	m_column++;
  10.681 +
  10.682 +	end = EvaluateExpressionAsInt();
  10.683 +
  10.684 +	if ( end < 0 || end > 0xFFFF )
  10.685 +	{
  10.686 +		throw AsmException_SyntaxError_OutOfRange( m_line, m_column );
  10.687 +	}
  10.688 +
  10.689 +	// get optional exec address
  10.690 +	// we allow this to be a forward define as it needn't be within the block we actually save
  10.691 +
  10.692 +	if ( m_line[ m_column ] == ',' )
  10.693 +	{
  10.694 +		m_column++;
  10.695 +
  10.696 +		try
  10.697 +		{
  10.698 +			exec = EvaluateExpressionAsInt();
  10.699 +		}
  10.700 +		catch ( AsmException_SyntaxError_SymbolNotDefined& e )
  10.701 +		{
  10.702 +			if ( GlobalData::Instance().IsSecondPass() )
  10.703 +			{
  10.704 +				throw;
  10.705 +			}
  10.706 +		}
  10.707 +	}
  10.708 +	else
  10.709 +	{
  10.710 +		exec = start;
  10.711 +	}
  10.712 +
  10.713 +	if ( exec < 0 || exec > 0xFFFF )
  10.714 +	{
  10.715 +		throw AsmException_SyntaxError_OutOfRange( m_line, m_column );
  10.716 +	}
  10.717 +
  10.718 +	// expect no more
  10.719 +
  10.720 +	if ( AdvanceAndCheckEndOfStatement() )
  10.721 +	{
  10.722 +		// found something else - wrong!
  10.723 +		throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column );
  10.724 +	}
  10.725 +
  10.726 +	// OK - do it
  10.727 +
  10.728 +	if ( GlobalData::Instance().IsSecondPass() )
  10.729 +	{
  10.730 +		if ( GlobalData::Instance().UsesDiscImage() )
  10.731 +		{
  10.732 +			// disc image version of the save
  10.733 +			GlobalData::Instance().GetDiscImage()->AddFile( saveFile.c_str(),
  10.734 +															ObjectCode::Instance().GetAddr( start ),
  10.735 +															start,
  10.736 +															exec,
  10.737 +															end - start );
  10.738 +		}
  10.739 +		else
  10.740 +		{
  10.741 +			// regular save
  10.742 +			ofstream objFile;
  10.743 +
  10.744 +			objFile.open( saveFile.c_str(), ios_base::out | ios_base::binary | ios_base::trunc );
  10.745 +
  10.746 +			if ( !objFile )
  10.747 +			{
  10.748 +				throw AsmException_FileError_OpenObj( saveFile.c_str() );
  10.749 +			}
  10.750 +
  10.751 +			if ( !objFile.write( reinterpret_cast< const char* >( ObjectCode::Instance().GetAddr( start ) ), end - start ) )
  10.752 +			{
  10.753 +				throw AsmException_FileError_WriteObj( saveFile.c_str() );
  10.754 +			}
  10.755 +
  10.756 +			objFile.close();
  10.757 +		}
  10.758 +	}
  10.759 +}
  10.760 +
  10.761 +
  10.762 +
  10.763 +/*************************************************************************************************/
  10.764 +/**
  10.765 +	LineParser::HandleFor()
  10.766 +*/
  10.767 +/*************************************************************************************************/
  10.768 +void LineParser::HandleFor()
  10.769 +{
  10.770 +	// syntax is FOR variable, exp, exp [, exp]
  10.771 +
  10.772 +	if ( !AdvanceAndCheckEndOfStatement() )
  10.773 +	{
  10.774 +		// found nothing
  10.775 +		throw AsmException_SyntaxError_EmptyExpression( m_line, m_column );
  10.776 +	}
  10.777 +
  10.778 +	// first look for the variable name
  10.779 +
  10.780 +	if ( !isalpha( m_line[ m_column ] ) && m_line[ m_column ] != '_' )
  10.781 +	{
  10.782 +		throw AsmException_SyntaxError_InvalidSymbolName( m_line, m_column );
  10.783 +	}
  10.784 +
  10.785 +	// Symbol starts with a valid character
  10.786 +
  10.787 +	int oldColumn = m_column;
  10.788 +	string symbolName = GetSymbolName() + m_sourceFile->GetSymbolNameSuffix();
  10.789 +
  10.790 +	// Check variable has not yet been defined
  10.791 +
  10.792 +	if ( SymbolTable::Instance().IsSymbolDefined( symbolName ) )
  10.793 +	{
  10.794 +		throw AsmException_SyntaxError_LabelAlreadyDefined( m_line, oldColumn );
  10.795 +	}
  10.796 +
  10.797 +	// look for first comma
  10.798 +
  10.799 +	if ( !AdvanceAndCheckEndOfStatement() )
  10.800 +	{
  10.801 +		// found nothing
  10.802 +		throw AsmException_SyntaxError_EmptyExpression( m_line, m_column );
  10.803 +	}
  10.804 +
  10.805 +	if ( m_line[ m_column ] != ',' )
  10.806 +	{
  10.807 +		throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column );
  10.808 +	}
  10.809 +	m_column++;
  10.810 +
  10.811 +	// look for start value
  10.812 +
  10.813 +	double start = EvaluateExpression();
  10.814 +
  10.815 +	// look for comma
  10.816 +
  10.817 +	if ( !AdvanceAndCheckEndOfStatement() )
  10.818 +	{
  10.819 +		// found nothing
  10.820 +		throw AsmException_SyntaxError_EmptyExpression( m_line, m_column );
  10.821 +	}
  10.822 +
  10.823 +	if ( m_line[ m_column ] != ',' )
  10.824 +	{
  10.825 +		throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column );
  10.826 +	}
  10.827 +
  10.828 +	m_column++;
  10.829 +
  10.830 +	// look for end value
  10.831 +
  10.832 +	double end = EvaluateExpression();
  10.833 +
  10.834 +	double step = 1.0;
  10.835 +
  10.836 +	if ( AdvanceAndCheckEndOfStatement() )
  10.837 +	{
  10.838 +		// look for step variable
  10.839 +
  10.840 +		if ( m_line[ m_column ] != ',' )
  10.841 +		{
  10.842 +			throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column );
  10.843 +		}
  10.844 +
  10.845 +		m_column++;
  10.846 +
  10.847 +		step = EvaluateExpression();
  10.848 +
  10.849 +		if ( step == 0.0 )
  10.850 +		{
  10.851 +			throw AsmException_SyntaxError_BadStep( m_line, m_column );
  10.852 +		}
  10.853 +
  10.854 +		// check this is now the end
  10.855 +
  10.856 +		if ( AdvanceAndCheckEndOfStatement() )
  10.857 +		{
  10.858 +			throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column );
  10.859 +		}
  10.860 +
  10.861 +	}
  10.862 +
  10.863 +	m_sourceFile->AddFor( symbolName,
  10.864 +						  start, end, step,
  10.865 +						  m_sourceFile->GetFilePointer() + m_column,
  10.866 +						  m_line,
  10.867 +						  oldColumn );
  10.868 +}
  10.869 +
  10.870 +
  10.871 +
  10.872 +/*************************************************************************************************/
  10.873 +/**
  10.874 +	LineParser::HandleNext()
  10.875 +*/
  10.876 +/*************************************************************************************************/
  10.877 +void LineParser::HandleNext()
  10.878 +{
  10.879 +	int oldColumn = m_column;
  10.880 +
  10.881 +	if ( AdvanceAndCheckEndOfStatement() )
  10.882 +	{
  10.883 +		// found nothing
  10.884 +		throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column );
  10.885 +	}
  10.886 +
  10.887 +	m_sourceFile->UpdateFor( m_line, oldColumn );
  10.888 +}
  10.889 +
  10.890 +
  10.891 +
  10.892 +/*************************************************************************************************/
  10.893 +/**
  10.894 +	LineParser::HandleIf()
  10.895 +*/
  10.896 +/*************************************************************************************************/
  10.897 +void LineParser::HandleIf()
  10.898 +{
  10.899 +	int condition = EvaluateExpressionAsInt();
  10.900 +	m_sourceFile->SetCurrentIfCondition( condition );
  10.901 +
  10.902 +	if ( m_line[ m_column ] == ',' )
  10.903 +	{
  10.904 +		// Unexpected comma (remembering that an expression can validly end with a comma)
  10.905 +		throw AsmException_SyntaxError_UnexpectedComma( m_line, m_column );
  10.906 +	}
  10.907 +}
  10.908 +
  10.909 +
  10.910 +
  10.911 +/*************************************************************************************************/
  10.912 +/**
  10.913 +	LineParser::HandleElse()
  10.914 +*/
  10.915 +/*************************************************************************************************/
  10.916 +void LineParser::HandleElse()
  10.917 +{
  10.918 +	if ( AdvanceAndCheckEndOfStatement() )
  10.919 +	{
  10.920 +		// found nothing
  10.921 +		throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column );
  10.922 +	}
  10.923 +}
  10.924 +
  10.925 +
  10.926 +
  10.927 +/*************************************************************************************************/
  10.928 +/**
  10.929 +	LineParser::HandleEndif()
  10.930 +*/
  10.931 +/*************************************************************************************************/
  10.932 +void LineParser::HandleEndif()
  10.933 +{
  10.934 +	if ( AdvanceAndCheckEndOfStatement() )
  10.935 +	{
  10.936 +		// found nothing
  10.937 +		throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column );
  10.938 +	}
  10.939 +}
  10.940 +
  10.941 +
  10.942 +
  10.943 +/*************************************************************************************************/
  10.944 +/**
  10.945 +	LineParser::HandlePrint()
  10.946 +
  10.947 +	Handle PRINT token.
  10.948 +
  10.949 +	Valid syntax:
  10.950 +	  PRINT
  10.951 +	  PRINT "string"
  10.952 +	  PRINT 2+7
  10.953 +	  PRINT someLabel
  10.954 +	  PRINT "someLabel =", someLabel, "someLabel in hex =", ~someLabel
  10.955 +*/
  10.956 +/*************************************************************************************************/
  10.957 +void LineParser::HandlePrint()
  10.958 +{
  10.959 +	bool bDemandComma = false;
  10.960 +
  10.961 +	while ( AdvanceAndCheckEndOfStatement() )
  10.962 +	{
  10.963 +		if ( m_line[ m_column ] == ',' )
  10.964 +		{
  10.965 +			// print separator - skip
  10.966 +			bDemandComma = false;
  10.967 +			m_column++;
  10.968 +		}
  10.969 +		else if ( bDemandComma )
  10.970 +		{
  10.971 +			throw AsmException_SyntaxError_MissingComma( m_line, m_column );
  10.972 +		}
  10.973 +		else if ( m_line[ m_column ] == '\"' )
  10.974 +		{
  10.975 +			// string
  10.976 +			size_t endQuotePos = m_line.find_first_of( '\"', m_column + 1 );
  10.977 +
  10.978 +			if ( endQuotePos == string::npos )
  10.979 +			{
  10.980 +				throw AsmException_SyntaxError_MissingQuote( m_line, m_line.length() );
  10.981 +			}
  10.982 +			else
  10.983 +			{
  10.984 +				if ( GlobalData::Instance().IsSecondPass() )
  10.985 +				{
  10.986 +					cout << m_line.substr( m_column + 1, endQuotePos - m_column - 1 ) << " ";
  10.987 +				}
  10.988 +			}
  10.989 +
  10.990 +			m_column = endQuotePos + 1;
  10.991 +			bDemandComma = true;
  10.992 +		}
  10.993 +		else if ( m_line[ m_column ] == '~' )
  10.994 +		{
  10.995 +			// print in hex
  10.996 +			m_column++;
  10.997 +
  10.998 +			int value;
  10.999 +
 10.1000 +			try
 10.1001 +			{
 10.1002 +				value = EvaluateExpressionAsInt();
 10.1003 +			}
 10.1004 +			catch ( AsmException_SyntaxError_SymbolNotDefined& e )
 10.1005 +			{
 10.1006 +				if ( GlobalData::Instance().IsFirstPass() )
 10.1007 +				{
 10.1008 +					value = 0;
 10.1009 +				}
 10.1010 +				else
 10.1011 +				{
 10.1012 +					throw;
 10.1013 +				}
 10.1014 +			}
 10.1015 +
 10.1016 +			if ( GlobalData::Instance().IsSecondPass() )
 10.1017 +			{
 10.1018 +				cout << hex << uppercase << "&" << value << dec << nouppercase << " ";
 10.1019 +			}
 10.1020 +		}
 10.1021 +		else
 10.1022 +		{
 10.1023 +			// print in dec
 10.1024 +
 10.1025 +			double value;
 10.1026 +
 10.1027 +			try
 10.1028 +			{
 10.1029 +				value = EvaluateExpression();
 10.1030 +			}
 10.1031 +			catch ( AsmException_SyntaxError_SymbolNotDefined& e )
 10.1032 +			{
 10.1033 +				if ( GlobalData::Instance().IsFirstPass() )
 10.1034 +				{
 10.1035 +					value = 0.0;
 10.1036 +				}
 10.1037 +				else
 10.1038 +				{
 10.1039 +					throw;
 10.1040 +				}
 10.1041 +			}
 10.1042 +
 10.1043 +			if ( GlobalData::Instance().IsSecondPass() )
 10.1044 +			{
 10.1045 +				cout << value << " ";
 10.1046 +			}
 10.1047 +		}
 10.1048 +	}
 10.1049 +
 10.1050 +	if ( GlobalData::Instance().IsSecondPass() )
 10.1051 +	{
 10.1052 +		cout << endl;
 10.1053 +	}
 10.1054 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/src/discimage.cpp	Sat May 01 19:35:42 2010 +0100
    11.3 @@ -0,0 +1,287 @@
    11.4 +/*************************************************************************************************/
    11.5 +/**
    11.6 +	discimage.cpp
    11.7 +*/
    11.8 +/*************************************************************************************************/
    11.9 +
   11.10 +#include "discimage.h"
   11.11 +#include "asmexception.h"
   11.12 +#include "globaldata.h"
   11.13 +
   11.14 +using namespace std;
   11.15 +
   11.16 +
   11.17 +/*************************************************************************************************/
   11.18 +/**
   11.19 +	DiscImage::DiscImage()
   11.20 +
   11.21 +	DiscImage constructor
   11.22 +*/
   11.23 +/*************************************************************************************************/
   11.24 +DiscImage::DiscImage( const char* pOutput, const char* pInput )
   11.25 +	:	m_outputFilename( pOutput ),
   11.26 +		m_inputFilename( pInput )
   11.27 +{
   11.28 +	// open output file
   11.29 +
   11.30 +	m_outputFile.open( pOutput, ios_base::out | ios_base::binary | ios_base::trunc );
   11.31 +
   11.32 +	if ( !m_outputFile )
   11.33 +	{
   11.34 +		throw AsmException_FileError_OpenDiscDest( pOutput );
   11.35 +	}
   11.36 +
   11.37 +	// open and load input file if necessary
   11.38 +
   11.39 +	if ( pInput != NULL )
   11.40 +	{
   11.41 +		m_inputFile.open( pInput, ios_base::in | ios_base::binary );
   11.42 +
   11.43 +		if ( !m_inputFile )
   11.44 +		{
   11.45 +			throw AsmException_FileError_OpenDiscSource( pInput );
   11.46 +		}
   11.47 +
   11.48 +		if ( !m_inputFile.read( reinterpret_cast< char* >( m_aCatalog ), 0x200 ) )
   11.49 +		{
   11.50 +			throw AsmException_FileError_ReadDiscSource( pInput );
   11.51 +		}
   11.52 +
   11.53 +		// copy the disc contents to the output file
   11.54 +
   11.55 +		int endSectorAddr;
   11.56 +
   11.57 +		if ( m_aCatalog[ 0x105 ] > 0 )
   11.58 +		{
   11.59 +			int sectorAddrOfLastFile	= m_aCatalog[ 0x10F ] +
   11.60 +										  ( ( m_aCatalog[ 0x10E ] & 0x03 ) << 8 );
   11.61 +
   11.62 +			int lengthOfLastFile		= m_aCatalog[ 0x10C ] +
   11.63 +										  ( m_aCatalog[ 0x10D ] << 8 ) +
   11.64 +										  ( ( m_aCatalog[ 0x10E ] & 0x30 ) << 12 );
   11.65 +
   11.66 +			endSectorAddr = sectorAddrOfLastFile + ( ( lengthOfLastFile + 0xFF ) >> 8 );
   11.67 +		}
   11.68 +		else
   11.69 +		{
   11.70 +			endSectorAddr = 2;
   11.71 +		}
   11.72 +
   11.73 +		m_inputFile.seekg( 0, ios::end );
   11.74 +		int length = m_inputFile.tellg();
   11.75 +		m_inputFile.seekg( 0, ios::beg );
   11.76 +
   11.77 +		assert( length >= endSectorAddr * 0x100 );
   11.78 +
   11.79 +		char sector[ 0x100 ];
   11.80 +
   11.81 +		for ( int sect = 0; sect < endSectorAddr; sect++ )
   11.82 +		{
   11.83 +			if ( !m_inputFile.read( sector, 0x100 ) )
   11.84 +			{
   11.85 +				throw AsmException_FileError_ReadDiscSource( pInput );
   11.86 +			}
   11.87 +
   11.88 +			if ( !m_outputFile.write( sector, 0x100 ) )
   11.89 +			{
   11.90 +				throw AsmException_FileError_WriteDiscDest( pOutput );
   11.91 +			}
   11.92 +		}
   11.93 +
   11.94 +	}
   11.95 +	else
   11.96 +	{
   11.97 +		// generate a blank catalog
   11.98 +
   11.99 +		memset( m_aCatalog, 0, 0x200 );
  11.100 +		m_aCatalog[ 0x106 ] = 0x33;
  11.101 +		m_aCatalog[ 0x107 ] = 0x20;
  11.102 +
  11.103 +		if ( !m_outputFile.write( reinterpret_cast< char* >( m_aCatalog ), 0x200 ) )
  11.104 +		{
  11.105 +			// write error
  11.106 +			throw AsmException_FileError_WriteDiscDest( m_outputFilename );
  11.107 +		}
  11.108 +
  11.109 +		// add in a boot file
  11.110 +
  11.111 +		if ( GlobalData::Instance().GetBootFile() != NULL )
  11.112 +		{
  11.113 +			char pPlingBoot[ 64 ];
  11.114 +			strcpy( pPlingBoot, "*BASIC\r*RUN " );
  11.115 +			strcat( pPlingBoot, GlobalData::Instance().GetBootFile() );
  11.116 +			strcat( pPlingBoot, "\r" );
  11.117 +
  11.118 +			AddFile( "!Boot", reinterpret_cast< unsigned char* >( pPlingBoot ), 0, 0xFFFFFF, strlen( pPlingBoot ) );
  11.119 +		}
  11.120 +	}
  11.121 +
  11.122 +}
  11.123 +
  11.124 +
  11.125 +
  11.126 +/*************************************************************************************************/
  11.127 +/**
  11.128 +	DiscImage::~DiscImage()
  11.129 +
  11.130 +	DiscImage destructor
  11.131 +*/
  11.132 +/*************************************************************************************************/
  11.133 +DiscImage::~DiscImage()
  11.134 +{
  11.135 +	// write back the catalog
  11.136 +
  11.137 +	m_outputFile.seekp( 0, ios::beg );
  11.138 +	if ( !m_outputFile.write( reinterpret_cast< char* >( m_aCatalog ), 0x200 ) )
  11.139 +	{
  11.140 +		// don't throw an exception in the destructor, just bear it silently..!
  11.141 +	}
  11.142 +
  11.143 +	m_outputFile.close();
  11.144 +	m_inputFile.close();
  11.145 +}
  11.146 +
  11.147 +
  11.148 +
  11.149 +/*************************************************************************************************/
  11.150 +/**
  11.151 +	DiscImage::AddFile()
  11.152 +*/
  11.153 +/*************************************************************************************************/
  11.154 +void DiscImage::AddFile( const char* pName, const unsigned char* pAddr, int load, int exec, int len )
  11.155 +{
  11.156 +	(void)pAddr;
  11.157 +
  11.158 +	if ( strlen( pName ) > 7 )
  11.159 +	{
  11.160 +		// Bad name
  11.161 +		throw AsmException_FileError_BadName( m_outputFilename );
  11.162 +	}
  11.163 +
  11.164 +	if ( m_aCatalog[ 0x105 ] == 31*8 )
  11.165 +	{
  11.166 +		// Catalog full
  11.167 +		throw AsmException_FileError_TooManyFiles( m_outputFilename );
  11.168 +	}
  11.169 +
  11.170 +	// Check the file doesn't already exist
  11.171 +
  11.172 +	for ( int i = m_aCatalog[ 0x105 ]; i > 0; i -= 8 )
  11.173 +	{
  11.174 +		bool bTheSame = true;
  11.175 +
  11.176 +		for ( size_t j = 0; j < 7 || j < strlen( pName ); j++ )
  11.177 +		{
  11.178 +			if ( toupper( pName[ j ] ) != toupper( m_aCatalog[ i + j ] ) )
  11.179 +			{
  11.180 +				bTheSame = false;
  11.181 +				break;
  11.182 +			}
  11.183 +		}
  11.184 +
  11.185 +		if ( bTheSame && ( m_aCatalog[ i + 7 ] & 0x7F ) == '$' )
  11.186 +		{
  11.187 +			// File already exists
  11.188 +			throw AsmException_FileError_FileExists( m_outputFilename );
  11.189 +		}
  11.190 +	}
  11.191 +
  11.192 +	// Calculate sector address for the new file
  11.193 +
  11.194 +	int sectorAddrOfThisFile;
  11.195 +
  11.196 +	if ( m_aCatalog[ 0x105 ] > 0 )
  11.197 +	{
  11.198 +		int sectorAddrOfLastFile	= m_aCatalog[ 0x10F ] +
  11.199 +									  ( ( m_aCatalog[ 0x10E ] & 0x03 ) << 8 );
  11.200 +
  11.201 +		int lengthOfLastFile		= m_aCatalog[ 0x10C ] +
  11.202 +									  ( m_aCatalog[ 0x10D ] << 8 ) +
  11.203 +									  ( ( m_aCatalog[ 0x10E ] & 0x30 ) << 12 );
  11.204 +
  11.205 +		sectorAddrOfThisFile = sectorAddrOfLastFile + ( ( lengthOfLastFile + 0xFF ) >> 8 );
  11.206 +	}
  11.207 +	else
  11.208 +	{
  11.209 +		sectorAddrOfThisFile = 2;
  11.210 +	}
  11.211 +
  11.212 +	int sectorLengthOfThisFile	= ( len + 0xFF ) >> 8;
  11.213 +
  11.214 +	if ( sectorAddrOfThisFile + sectorLengthOfThisFile > 800 )
  11.215 +	{
  11.216 +		// Disc full
  11.217 +		throw AsmException_FileError_DiscFull( m_outputFilename );
  11.218 +	}
  11.219 +
  11.220 +	// Make space in the catalog for the new file
  11.221 +
  11.222 +	for ( int i = m_aCatalog[ 0x105 ]; i > 0; i -= 8 )
  11.223 +	{
  11.224 +		for ( int j = 0; j < 8; j++ )
  11.225 +		{
  11.226 +			m_aCatalog[ i + j + 8 ] = m_aCatalog[ i + j ];
  11.227 +			m_aCatalog[ i + j + 0x108 ] = m_aCatalog[ i + j + 0x100 ];
  11.228 +		}
  11.229 +	}
  11.230 +
  11.231 +	// Increment the file count
  11.232 +
  11.233 +	m_aCatalog[ 0x105 ] += 8;
  11.234 +
  11.235 +	// Write filename
  11.236 +
  11.237 +	for ( size_t j = 0; j < 7; j++ )
  11.238 +	{
  11.239 +		m_aCatalog[ j + 8 ] = ( j < strlen( pName ) ) ? pName[ j ] : ' ';
  11.240 +	}
  11.241 +
  11.242 +	// Write directory name
  11.243 +
  11.244 +	m_aCatalog[ 15 ] = '$';
  11.245 +
  11.246 +	// Write load address
  11.247 +
  11.248 +	m_aCatalog[ 0x108 ] = load & 0xFF;
  11.249 +	m_aCatalog[ 0x109 ] = ( load & 0xFF00 ) >> 8;
  11.250 +
  11.251 +	// Write exec address
  11.252 +
  11.253 +	m_aCatalog[ 0x10A ] = exec & 0xFF;
  11.254 +	m_aCatalog[ 0x10B ] = ( exec & 0xFF00 ) >> 8;
  11.255 +
  11.256 +	// Write length
  11.257 +
  11.258 +	m_aCatalog[ 0x10C ] = len & 0xFF;
  11.259 +	m_aCatalog[ 0x10D ] = ( len & 0xFF00 ) >> 8;
  11.260 +
  11.261 +	// Write sector start
  11.262 +
  11.263 +	m_aCatalog[ 0x10F ] = sectorAddrOfThisFile & 0xFF;
  11.264 +
  11.265 +	// Write miscellaneous bits
  11.266 +
  11.267 +	m_aCatalog[ 0x10E ] = ( ( ( load >> 16 ) & 0x03 ) << 2 ) |
  11.268 +						  ( ( ( exec >> 16 ) & 0x03 ) << 6 ) |
  11.269 +						  ( ( ( len  >> 16 ) & 0x03 ) << 4 ) |
  11.270 +						  ( ( sectorAddrOfThisFile >> 8 ) & 0x03 );
  11.271 +
  11.272 +	// Now write the actual file
  11.273 +
  11.274 +	assert( static_cast< int >( m_outputFile.tellp() ) == sectorAddrOfThisFile * 0x100 );
  11.275 +
  11.276 +	if ( !m_outputFile.write( reinterpret_cast< const char* >( pAddr ), len ) )
  11.277 +	{
  11.278 +		// Write error
  11.279 +		throw AsmException_FileError_WriteDiscDest( m_outputFilename );
  11.280 +	}
  11.281 +
  11.282 +	while ( ( m_outputFile.tellp() & 0xFF ) != 0 )
  11.283 +	{
  11.284 +		if ( !m_outputFile.put( 0 ) )
  11.285 +		{
  11.286 +			// Write error
  11.287 +			throw AsmException_FileError_WriteDiscDest( m_outputFilename );
  11.288 +		}
  11.289 +	}
  11.290 +}
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/src/discimage.h	Sat May 01 19:35:42 2010 +0100
    12.3 @@ -0,0 +1,35 @@
    12.4 +/*************************************************************************************************/
    12.5 +/**
    12.6 +	discimage.h
    12.7 +*/
    12.8 +/*************************************************************************************************/
    12.9 +
   12.10 +#ifndef DISCIMAGE_H_
   12.11 +#define DISCIMAGE_H_
   12.12 +
   12.13 +#include <fstream>
   12.14 +
   12.15 +
   12.16 +class DiscImage
   12.17 +{
   12.18 +public:
   12.19 +
   12.20 +	explicit DiscImage( const char* pOutput, const char* pInput = NULL );
   12.21 +	~DiscImage();
   12.22 +
   12.23 +	void AddFile( const char* pName, const unsigned char* pAddr, int load, int exec, int len );
   12.24 +
   12.25 +
   12.26 +private:
   12.27 +
   12.28 +	std::ofstream				m_outputFile;
   12.29 +	std::ifstream				m_inputFile;
   12.30 +	const char*					m_outputFilename;
   12.31 +	const char*					m_inputFilename;
   12.32 +	unsigned char				m_aCatalog[ 0x200 ];
   12.33 +
   12.34 +};
   12.35 +
   12.36 +
   12.37 +
   12.38 +#endif // DISCIMAGE_H_
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/src/expression.cpp	Sat May 01 19:35:42 2010 +0100
    13.3 @@ -0,0 +1,1136 @@
    13.4 +/*************************************************************************************************/
    13.5 +/**
    13.6 +	expression.cpp
    13.7 +
    13.8 +	Contains all the LineParser methods for parsing and evaluating expressions
    13.9 +*/
   13.10 +/*************************************************************************************************/
   13.11 +
   13.12 +#include <cmath>
   13.13 +#include <sstream>
   13.14 +#include <iomanip>
   13.15 +
   13.16 +#include "lineparser.h"
   13.17 +#include "asmexception.h"
   13.18 +#include "symboltable.h"
   13.19 +#include "globaldata.h"
   13.20 +#include "objectcode.h"
   13.21 +#include "sourcefile.h"
   13.22 +
   13.23 +
   13.24 +using namespace std;
   13.25 +
   13.26 +
   13.27 +
   13.28 +LineParser::Operator	LineParser::m_gaBinaryOperatorTable[] =
   13.29 +{
   13.30 +	{ ")",		-1,	NULL },		// special case
   13.31 +	{ "]",		-1,	NULL },		// special case
   13.32 +
   13.33 +	{ "^",		7,	&LineParser::EvalPower },
   13.34 +	{ "*",		6,	&LineParser::EvalMultiply },
   13.35 +	{ "/",		6,	&LineParser::EvalDivide },
   13.36 +	{ "%",		6,	&LineParser::EvalMod },
   13.37 +	{ "DIV",	6,	&LineParser::EvalDiv },
   13.38 +	{ "MOD",	6,	&LineParser::EvalMod },
   13.39 +	{ "<<",		6,	&LineParser::EvalShiftLeft },
   13.40 +	{ ">>",		6,	&LineParser::EvalShiftRight },
   13.41 +	{ "+",		5,	&LineParser::EvalAdd },
   13.42 +	{ "-",		5,	&LineParser::EvalSubtract },
   13.43 +	{ "==",		4,	&LineParser::EvalEqual },
   13.44 +	{ "=",		4,	&LineParser::EvalEqual },
   13.45 +	{ "<>",		4,	&LineParser::EvalNotEqual },
   13.46 +	{ "!=",		4,	&LineParser::EvalNotEqual },
   13.47 +	{ "<=",		4,	&LineParser::EvalLessThanOrEqual },
   13.48 +	{ ">=",		4,	&LineParser::EvalMoreThanOrEqual },
   13.49 +	{ "<",		4,	&LineParser::EvalLessThan },
   13.50 +	{ ">",		4,	&LineParser::EvalMoreThan },
   13.51 +	{ "AND",	3,	&LineParser::EvalAnd },
   13.52 +	{ "OR",		2,	&LineParser::EvalOr },
   13.53 +	{ "EOR",	2,	&LineParser::EvalEor }
   13.54 +};
   13.55 +
   13.56 +
   13.57 +
   13.58 +LineParser::Operator	LineParser::m_gaUnaryOperatorTable[] =
   13.59 +{
   13.60 +	{ "(",		-1,	NULL },		// special case
   13.61 +	{ "[",		-1,	NULL },		// special case
   13.62 +
   13.63 +	{ "-",		8,	&LineParser::EvalNegate },
   13.64 +	{ "+",		8,	&LineParser::EvalPosate },
   13.65 +	{ "HI",		10,	&LineParser::EvalHi },
   13.66 +	{ "LO",		10,	&LineParser::EvalLo },
   13.67 +	{ "<",		10,	&LineParser::EvalHi },
   13.68 +	{ ">",		10,	&LineParser::EvalLo },
   13.69 +	{ "SIN",	10, &LineParser::EvalSin },
   13.70 +	{ "COS",	10, &LineParser::EvalCos },
   13.71 +	{ "TAN",	10, &LineParser::EvalTan },
   13.72 +	{ "ASN",	10, &LineParser::EvalArcSin },
   13.73 +	{ "ACS",	10, &LineParser::EvalArcCos },
   13.74 +	{ "ATN",	10, &LineParser::EvalArcTan },
   13.75 +	{ "SQR",	10, &LineParser::EvalSqrt },
   13.76 +	{ "RAD",	10, &LineParser::EvalDegToRad },
   13.77 +	{ "DEG",	10, &LineParser::EvalRadToDeg },
   13.78 +	{ "INT",	10,	&LineParser::EvalInt },
   13.79 +	{ "ABS",	10, &LineParser::EvalAbs },
   13.80 +	{ "SGN",	10, &LineParser::EvalSgn },
   13.81 +	{ "RND",	10,	&LineParser::EvalRnd }
   13.82 +};
   13.83 +
   13.84 +
   13.85 +
   13.86 +/*************************************************************************************************/
   13.87 +/**
   13.88 +	LineParser::GetValue()
   13.89 +
   13.90 +	Parses a simple value.  This may be
   13.91 +	- a decimal literal
   13.92 +	- a hex literal (prefixed by &)
   13.93 +	- a symbol (label)
   13.94 +	- a special value such as * (PC)
   13.95 +
   13.96 +	@return		double
   13.97 +*/
   13.98 +/*************************************************************************************************/
   13.99 +double LineParser::GetValue()
  13.100 +{
  13.101 +	double value = 0;
  13.102 +
  13.103 +	if ( isdigit( m_line[ m_column ] ) || m_line[ m_column ] == '.' )
  13.104 +	{
  13.105 +		// get a number
  13.106 +
  13.107 +		istringstream str( m_line );
  13.108 +		str.seekg( m_column );
  13.109 +		str >> value;
  13.110 +		m_column = str.tellg();
  13.111 +	}
  13.112 +	else if ( m_line[ m_column ] == '&' )
  13.113 +	{
  13.114 +		// get a hex digit
  13.115 +
  13.116 +		m_column++;
  13.117 +
  13.118 +		if ( !isxdigit( m_line[ m_column ] ) )
  13.119 +		{
  13.120 +			// badly formed hex literal
  13.121 +			throw AsmException_SyntaxError_BadHex( m_line, m_column );
  13.122 +		}
  13.123 +		else
  13.124 +		{
  13.125 +			// get a number
  13.126 +
  13.127 +			int hexValue;
  13.128 +
  13.129 +			istringstream str( m_line );
  13.130 +			str.seekg( m_column );
  13.131 +			str >> hex >> hexValue;
  13.132 +			m_column = str.tellg();
  13.133 +
  13.134 +			value = static_cast< double >( hexValue );
  13.135 +		}
  13.136 +	}
  13.137 +	else if ( m_line[ m_column ] == '*' )
  13.138 +	{
  13.139 +		// get current PC
  13.140 +
  13.141 +		m_column++;
  13.142 +		value = static_cast< double >( ObjectCode::Instance().GetPC() );
  13.143 +	}
  13.144 +	else if ( m_line[ m_column ] == '\'' )
  13.145 +	{
  13.146 +		// get char literal
  13.147 +
  13.148 +		if ( m_line.length() - m_column < 3 ||  m_line[ m_column + 2 ] != '\'' )
  13.149 +		{
  13.150 +			// bad syntax - must be e.g. 'A'
  13.151 +			throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column );
  13.152 +		}
  13.153 +
  13.154 +		value = static_cast< double >( m_line[ m_column + 1 ] );
  13.155 +		m_column += 3;
  13.156 +	}
  13.157 +	else if ( isalpha( m_line[ m_column ] ) || m_line[ m_column ] == '_' )
  13.158 +	{
  13.159 +		// get a symbol
  13.160 +
  13.161 +		int oldColumn = m_column;
  13.162 +		string symbolName = GetSymbolName();
  13.163 +		bool bFoundSymbol = false;
  13.164 +
  13.165 +		for ( int forLevel = m_sourceFile->GetForLevel(); forLevel >= 0; forLevel-- )
  13.166 +		{
  13.167 +			string fullSymbolName = symbolName + m_sourceFile->GetSymbolNameSuffix( forLevel );
  13.168 +
  13.169 +			if ( SymbolTable::Instance().IsSymbolDefined( fullSymbolName ) )
  13.170 +			{
  13.171 +				value = SymbolTable::Instance().GetSymbol( fullSymbolName );
  13.172 +				bFoundSymbol = true;
  13.173 +				break;
  13.174 +			}
  13.175 +		}
  13.176 +
  13.177 +		if ( !bFoundSymbol )
  13.178 +		{
  13.179 +			// symbol not known
  13.180 +			throw AsmException_SyntaxError_SymbolNotDefined( m_line, oldColumn );
  13.181 +		}
  13.182 +	}
  13.183 +	else
  13.184 +	{
  13.185 +		// expected value
  13.186 +		throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column );
  13.187 +	}
  13.188 +
  13.189 +	return value;
  13.190 +}
  13.191 +
  13.192 +
  13.193 +
  13.194 +/*************************************************************************************************/
  13.195 +/**
  13.196 +	LineParser::EvaluateExpression()
  13.197 +
  13.198 +	Evaluates an expression, and returns its value, also advancing the string pointer
  13.199 +*/
  13.200 +/*************************************************************************************************/
  13.201 +double LineParser::EvaluateExpression( bool bAllowOneMismatchedCloseBracket )
  13.202 +{
  13.203 +	// Reset stacks
  13.204 +
  13.205 +	m_valueStackPtr = 0;
  13.206 +	m_operatorStackPtr = 0;
  13.207 +
  13.208 +	TYPE expected = VALUE_OR_UNARY;
  13.209 +
  13.210 +	// Iterate through the expression
  13.211 +
  13.212 +	while ( AdvanceAndCheckEndOfSubStatement() )
  13.213 +	{
  13.214 +		if ( expected == VALUE_OR_UNARY )
  13.215 +		{
  13.216 +			// Look for unary operator
  13.217 +
  13.218 +			int matchedToken = -1;
  13.219 +
  13.220 +			// Check against unary operator tokens
  13.221 +
  13.222 +			for ( unsigned int i = 0; i < sizeof m_gaUnaryOperatorTable / sizeof(Operator); i++ )
  13.223 +			{
  13.224 +				const char*		token	= m_gaUnaryOperatorTable[ i ].token;
  13.225 +				size_t			len		= strlen( token );
  13.226 +
  13.227 +				// see if token matches
  13.228 +
  13.229 +				if ( m_line.compare( m_column, len, token ) == 0 )
  13.230 +				{
  13.231 +					matchedToken = i;
  13.232 +					m_column += len;
  13.233 +					break;
  13.234 +				}
  13.235 +			}
  13.236 +
  13.237 +			if ( matchedToken == -1 )
  13.238 +			{
  13.239 +				// If unary operator not found, look for a value instead
  13.240 +
  13.241 +				if ( m_valueStackPtr == MAX_VALUES )
  13.242 +				{
  13.243 +					throw AsmException_SyntaxError_ExpressionTooComplex( m_line, m_column );
  13.244 +				}
  13.245 +
  13.246 +				double value;
  13.247 +
  13.248 +				try
  13.249 +				{
  13.250 +					value = GetValue();
  13.251 +				}
  13.252 +				catch ( AsmException_SyntaxError_SymbolNotDefined& e )
  13.253 +				{
  13.254 +					// If we encountered an unknown symbol whilst evaluating the expression...
  13.255 +
  13.256 +					if ( GlobalData::Instance().IsFirstPass() )
  13.257 +					{
  13.258 +						// On first pass, we have to continue gracefully.
  13.259 +						// This loop moves the string pointer to beyond the expression
  13.260 +
  13.261 +						while ( AdvanceAndCheckEndOfSubStatement() )
  13.262 +						{
  13.263 +							m_column++;
  13.264 +						}
  13.265 +					}
  13.266 +
  13.267 +					// Whatever happens, we throw the exception
  13.268 +					throw;
  13.269 +				}
  13.270 +
  13.271 +				m_valueStack[ m_valueStackPtr++ ] = value;
  13.272 +				expected = BINARY;
  13.273 +			}
  13.274 +			else
  13.275 +			{
  13.276 +				// If unary operator *was* found...
  13.277 +
  13.278 +				Operator& thisOp = m_gaUnaryOperatorTable[ matchedToken ];
  13.279 +
  13.280 +				if ( thisOp.handler != NULL )
  13.281 +				{
  13.282 +					// not an open bracket - we may have to juggle the stack
  13.283 +
  13.284 +					while ( m_operatorStackPtr > 0 &&
  13.285 +							thisOp.precedence < m_operatorStack[ m_operatorStackPtr - 1 ].precedence )
  13.286 +					{
  13.287 +						m_operatorStackPtr--;
  13.288 +
  13.289 +						OperatorHandler opHandler = m_operatorStack[ m_operatorStackPtr ].handler;
  13.290 +						assert( opHandler != NULL );	// this should really not be possible!
  13.291 +
  13.292 +						( this->*opHandler )();
  13.293 +					}
  13.294 +				}
  13.295 +
  13.296 +				if ( m_operatorStackPtr == MAX_OPERATORS )
  13.297 +				{
  13.298 +					throw AsmException_SyntaxError_ExpressionTooComplex( m_line, m_column );
  13.299 +				}
  13.300 +
  13.301 +				m_operatorStack[ m_operatorStackPtr++ ] = thisOp;
  13.302 +			}
  13.303 +
  13.304 +		}
  13.305 +		else
  13.306 +		{
  13.307 +			// Get binary operator
  13.308 +
  13.309 +			int matchedToken = -1;
  13.310 +
  13.311 +			for ( unsigned int i = 0; i < sizeof m_gaBinaryOperatorTable / sizeof(Operator); i++ )
  13.312 +			{
  13.313 +				const char*		token	= m_gaBinaryOperatorTable[ i ].token;
  13.314 +				size_t			len		= strlen( token );
  13.315 +
  13.316 +				// see if token matches
  13.317 +
  13.318 +				if ( m_line.compare( m_column, len, token ) == 0 )
  13.319 +				{
  13.320 +					matchedToken = i;
  13.321 +					m_column += len;
  13.322 +					break;
  13.323 +				}
  13.324 +			}
  13.325 +
  13.326 +			if ( matchedToken == -1 )
  13.327 +			{
  13.328 +				// unrecognised binary op
  13.329 +				throw AsmException_SyntaxError_InvalidCharacter( m_line, m_column );
  13.330 +			}
  13.331 +
  13.332 +			// we found binary operator
  13.333 +
  13.334 +			Operator& thisOp = m_gaBinaryOperatorTable[ matchedToken ];
  13.335 +
  13.336 +			if ( thisOp.handler != NULL )
  13.337 +			{
  13.338 +				// not an close bracket
  13.339 +
  13.340 +				while ( m_operatorStackPtr > 0 &&
  13.341 +						thisOp.precedence <= m_operatorStack[ m_operatorStackPtr - 1 ].precedence )
  13.342 +				{
  13.343 +					m_operatorStackPtr--;
  13.344 +
  13.345 +					OperatorHandler opHandler = m_operatorStack[ m_operatorStackPtr ].handler;
  13.346 +					assert( opHandler != NULL );	// this means the operator has been given a precedence of < 0
  13.347 +
  13.348 +					( this->*opHandler )();
  13.349 +				}
  13.350 +
  13.351 +				if ( m_operatorStackPtr == MAX_OPERATORS )
  13.352 +				{
  13.353 +					throw AsmException_SyntaxError_ExpressionTooComplex( m_line, m_column );
  13.354 +				}
  13.355 +
  13.356 +				m_operatorStack[ m_operatorStackPtr++ ] = thisOp;
  13.357 +
  13.358 +				expected = VALUE_OR_UNARY;
  13.359 +			}
  13.360 +			else
  13.361 +			{
  13.362 +				// is a close bracket
  13.363 +
  13.364 +				bool bFoundMatchingBracket = false;
  13.365 +
  13.366 +				while ( m_operatorStackPtr > 0 )
  13.367 +				{
  13.368 +					m_operatorStackPtr--;
  13.369 +
  13.370 +					OperatorHandler opHandler = m_operatorStack[ m_operatorStackPtr ].handler;
  13.371 +					if ( opHandler != NULL )
  13.372 +					{
  13.373 +						( this->*opHandler )();
  13.374 +					}
  13.375 +					else
  13.376 +					{
  13.377 +						bFoundMatchingBracket = true;
  13.378 +						break;
  13.379 +					}
  13.380 +				}
  13.381 +
  13.382 +				if ( !bFoundMatchingBracket )
  13.383 +				{
  13.384 +					if ( bAllowOneMismatchedCloseBracket )
  13.385 +					{
  13.386 +						// this is a hack which allows an extra close bracket to terminate an expression,
  13.387 +						// so that we can parse LDA (ind),Y and JMP (ind) where the open bracket is not
  13.388 +						// included in the expression
  13.389 +
  13.390 +						m_column--;
  13.391 +						break;	// jump out of the loop, ready to exit
  13.392 +					}
  13.393 +					else
  13.394 +					{
  13.395 +						// mismatched brackets
  13.396 +						throw AsmException_SyntaxError_MismatchedParentheses( m_line, m_column - 1 );
  13.397 +					}
  13.398 +				}
  13.399 +			}
  13.400 +		}
  13.401 +	}
  13.402 +
  13.403 +	// purge the operator stack
  13.404 +
  13.405 +	while ( m_operatorStackPtr > 0 )
  13.406 +	{
  13.407 +		m_operatorStackPtr--;
  13.408 +
  13.409 +		OperatorHandler opHandler = m_operatorStack[ m_operatorStackPtr ].handler;
  13.410 +
  13.411 +		if ( opHandler == NULL )
  13.412 +		{
  13.413 +			// mismatched brackets
  13.414 +			throw AsmException_SyntaxError_MismatchedParentheses( m_line, m_column );
  13.415 +		}
  13.416 +		else
  13.417 +		{
  13.418 +			( this->*opHandler )();
  13.419 +		}
  13.420 +	}
  13.421 +
  13.422 +	assert( m_valueStackPtr <= 1 );
  13.423 +
  13.424 +	if ( m_valueStackPtr == 0 )
  13.425 +	{
  13.426 +		// nothing was found
  13.427 +		throw AsmException_SyntaxError_EmptyExpression( m_line, m_column );
  13.428 +	}
  13.429 +
  13.430 +	return m_valueStack[ 0 ];
  13.431 +}
  13.432 +
  13.433 +
  13.434 +
  13.435 +/*************************************************************************************************/
  13.436 +/**
  13.437 +	LineParser::EvaluateExpressionAsInt()
  13.438 +
  13.439 +	Version of EvaluateExpression which returns its result as an int
  13.440 +*/
  13.441 +/*************************************************************************************************/
  13.442 +int LineParser::EvaluateExpressionAsInt( bool bAllowOneMismatchedCloseBracket )
  13.443 +{
  13.444 +	return static_cast< int >( EvaluateExpression( bAllowOneMismatchedCloseBracket ) );
  13.445 +}
  13.446 +
  13.447 +
  13.448 +
  13.449 +/*************************************************************************************************/
  13.450 +/**
  13.451 +	LineParser::EvalAdd()
  13.452 +*/
  13.453 +/*************************************************************************************************/
  13.454 +void LineParser::EvalAdd()
  13.455 +{
  13.456 +	if ( m_valueStackPtr < 2 )
  13.457 +	{
  13.458 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.459 +	}
  13.460 +	m_valueStack[ m_valueStackPtr - 2 ] = m_valueStack[ m_valueStackPtr - 2 ] + m_valueStack[ m_valueStackPtr - 1 ];
  13.461 +	m_valueStackPtr--;
  13.462 +}
  13.463 +
  13.464 +
  13.465 +
  13.466 +/*************************************************************************************************/
  13.467 +/**
  13.468 +	LineParser::EvalSubtract()
  13.469 +*/
  13.470 +/*************************************************************************************************/
  13.471 +void LineParser::EvalSubtract()
  13.472 +{
  13.473 +	if ( m_valueStackPtr < 2 )
  13.474 +	{
  13.475 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.476 +	}
  13.477 +	m_valueStack[ m_valueStackPtr - 2 ] = m_valueStack[ m_valueStackPtr - 2 ] - m_valueStack[ m_valueStackPtr - 1 ];
  13.478 +	m_valueStackPtr--;
  13.479 +}
  13.480 +
  13.481 +
  13.482 +
  13.483 +/*************************************************************************************************/
  13.484 +/**
  13.485 +	LineParser::EvalMultiply()
  13.486 +*/
  13.487 +/*************************************************************************************************/
  13.488 +void LineParser::EvalMultiply()
  13.489 +{
  13.490 +	if ( m_valueStackPtr < 2 )
  13.491 +	{
  13.492 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.493 +	}
  13.494 +	m_valueStack[ m_valueStackPtr - 2 ] = m_valueStack[ m_valueStackPtr - 2 ] * m_valueStack[ m_valueStackPtr - 1 ];
  13.495 +	m_valueStackPtr--;
  13.496 +}
  13.497 +
  13.498 +
  13.499 +
  13.500 +/*************************************************************************************************/
  13.501 +/**
  13.502 +	LineParser::EvalDivide()
  13.503 +*/
  13.504 +/*************************************************************************************************/
  13.505 +void LineParser::EvalDivide()
  13.506 +{
  13.507 +	if ( m_valueStackPtr < 2 )
  13.508 +	{
  13.509 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.510 +	}
  13.511 +	if ( m_valueStack[ m_valueStackPtr - 1 ] == 0.0 )
  13.512 +	{
  13.513 +		throw AsmException_SyntaxError_DivisionByZero( m_line, m_column - 1 );
  13.514 +	}
  13.515 +	m_valueStack[ m_valueStackPtr - 2 ] = m_valueStack[ m_valueStackPtr - 2 ] / m_valueStack[ m_valueStackPtr - 1 ];
  13.516 +	m_valueStackPtr--;
  13.517 +}
  13.518 +
  13.519 +
  13.520 +
  13.521 +/*************************************************************************************************/
  13.522 +/**
  13.523 +	LineParser::EvalPower()
  13.524 +*/
  13.525 +/*************************************************************************************************/
  13.526 +void LineParser::EvalPower()
  13.527 +{
  13.528 +	if ( m_valueStackPtr < 2 )
  13.529 +	{
  13.530 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.531 +	}
  13.532 +	m_valueStack[ m_valueStackPtr - 2 ] = pow( m_valueStack[ m_valueStackPtr - 2 ], m_valueStack[ m_valueStackPtr - 1 ] );
  13.533 +	m_valueStackPtr--;
  13.534 +
  13.535 +	if ( errno == ERANGE )
  13.536 +	{
  13.537 +		throw AsmException_SyntaxError_NumberTooBig( m_line, m_column - 1 );
  13.538 +	}
  13.539 +
  13.540 +	if ( errno == EDOM )
  13.541 +	{
  13.542 +		throw AsmException_SyntaxError_IllegalOperation( m_line, m_column - 1 );
  13.543 +	}
  13.544 +}
  13.545 +
  13.546 +
  13.547 +
  13.548 +/*************************************************************************************************/
  13.549 +/**
  13.550 +	LineParser::EvalDiv()
  13.551 +*/
  13.552 +/*************************************************************************************************/
  13.553 +void LineParser::EvalDiv()
  13.554 +{
  13.555 +	if ( m_valueStackPtr < 2 )
  13.556 +	{
  13.557 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.558 +	}
  13.559 +	if ( m_valueStack[ m_valueStackPtr - 1 ] == 0.0 )
  13.560 +	{
  13.561 +		throw AsmException_SyntaxError_DivisionByZero( m_line, m_column - 1 );
  13.562 +	}
  13.563 +	m_valueStack[ m_valueStackPtr - 2 ] = static_cast< double >(
  13.564 +		static_cast< int >( m_valueStack[ m_valueStackPtr - 2 ] ) /
  13.565 +		static_cast< int >( m_valueStack[ m_valueStackPtr - 1 ] ) );
  13.566 +	m_valueStackPtr--;
  13.567 +}
  13.568 +
  13.569 +
  13.570 +
  13.571 +/*************************************************************************************************/
  13.572 +/**
  13.573 +	LineParser::EvalMod()
  13.574 +*/
  13.575 +/*************************************************************************************************/
  13.576 +void LineParser::EvalMod()
  13.577 +{
  13.578 +	if ( m_valueStackPtr < 2 )
  13.579 +	{
  13.580 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.581 +	}
  13.582 +	if ( m_valueStack[ m_valueStackPtr - 1 ] == 0.0 )
  13.583 +	{
  13.584 +		throw AsmException_SyntaxError_DivisionByZero( m_line, m_column - 1 );
  13.585 +	}
  13.586 +	m_valueStack[ m_valueStackPtr - 2 ] = static_cast< double >(
  13.587 +		static_cast< int >( m_valueStack[ m_valueStackPtr - 2 ] ) %
  13.588 +		static_cast< int >( m_valueStack[ m_valueStackPtr - 1 ] ) );
  13.589 +	m_valueStackPtr--;
  13.590 +}
  13.591 +
  13.592 +
  13.593 +
  13.594 +/*************************************************************************************************/
  13.595 +/**
  13.596 +	LineParser::EvalShiftLeft()
  13.597 +*/
  13.598 +/*************************************************************************************************/
  13.599 +void LineParser::EvalShiftLeft()
  13.600 +{
  13.601 +	if ( m_valueStackPtr < 2 )
  13.602 +	{
  13.603 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.604 +	}
  13.605 +	int val = static_cast< int >( m_valueStack[ m_valueStackPtr - 2 ] );
  13.606 +	int shift = static_cast< int >( m_valueStack[ m_valueStackPtr - 1 ] );
  13.607 +	int result;
  13.608 +
  13.609 +	if ( shift > 31 || shift < -31 )
  13.610 +	{
  13.611 +		result = 0;
  13.612 +	}
  13.613 +	else if ( shift > 0 )
  13.614 +	{
  13.615 +		result = val << shift;
  13.616 +	}
  13.617 +	else if ( shift == 0 )
  13.618 +	{
  13.619 +		result = val;
  13.620 +	}
  13.621 +	else
  13.622 +	{
  13.623 +		result = val >> (-shift);
  13.624 +	}
  13.625 +
  13.626 +	m_valueStack[ m_valueStackPtr - 2 ] = static_cast< double >( result );
  13.627 +	m_valueStackPtr--;
  13.628 +}
  13.629 +
  13.630 +
  13.631 +
  13.632 +/*************************************************************************************************/
  13.633 +/**
  13.634 +	LineParser::EvalShiftRight()
  13.635 +*/
  13.636 +/*************************************************************************************************/
  13.637 +void LineParser::EvalShiftRight()
  13.638 +{
  13.639 +	if ( m_valueStackPtr < 2 )
  13.640 +	{
  13.641 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.642 +	}
  13.643 +	int val = static_cast< int >( m_valueStack[ m_valueStackPtr - 2 ] );
  13.644 +	int shift = static_cast< int >( m_valueStack[ m_valueStackPtr - 1 ] );
  13.645 +	int result;
  13.646 +
  13.647 +	if ( shift > 31 || shift < -31 )
  13.648 +	{
  13.649 +		result = 0;
  13.650 +	}
  13.651 +	else if ( shift > 0 )
  13.652 +	{
  13.653 +		result = val >> shift;
  13.654 +	}
  13.655 +	else if ( shift == 0 )
  13.656 +	{
  13.657 +		result = val;
  13.658 +	}
  13.659 +	else
  13.660 +	{
  13.661 +		result = val << (-shift);
  13.662 +	}
  13.663 +
  13.664 +	m_valueStack[ m_valueStackPtr - 2 ] = static_cast< double >( result );
  13.665 +	m_valueStackPtr--;
  13.666 +}
  13.667 +
  13.668 +
  13.669 +
  13.670 +/*************************************************************************************************/
  13.671 +/**
  13.672 +	LineParser::EvalAnd()
  13.673 +*/
  13.674 +/*************************************************************************************************/
  13.675 +void LineParser::EvalAnd()
  13.676 +{
  13.677 +	if ( m_valueStackPtr < 2 )
  13.678 +	{
  13.679 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.680 +	}
  13.681 +	m_valueStack[ m_valueStackPtr - 2 ] = static_cast< double >(
  13.682 +		static_cast< int >( m_valueStack[ m_valueStackPtr - 2 ] ) &
  13.683 +		static_cast< int >( m_valueStack[ m_valueStackPtr - 1 ] ) );
  13.684 +	m_valueStackPtr--;
  13.685 +}
  13.686 +
  13.687 +
  13.688 +
  13.689 +/*************************************************************************************************/
  13.690 +/**
  13.691 +	LineParser::EvalOr()
  13.692 +*/
  13.693 +/*************************************************************************************************/
  13.694 +void LineParser::EvalOr()
  13.695 +{
  13.696 +	if ( m_valueStackPtr < 2 )
  13.697 +	{
  13.698 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.699 +	}
  13.700 +	m_valueStack[ m_valueStackPtr - 2 ] = static_cast< double >(
  13.701 +		static_cast< int >( m_valueStack[ m_valueStackPtr - 2 ] ) |
  13.702 +		static_cast< int >( m_valueStack[ m_valueStackPtr - 1 ] ) );
  13.703 +	m_valueStackPtr--;
  13.704 +}
  13.705 +
  13.706 +
  13.707 +
  13.708 +/*************************************************************************************************/
  13.709 +/**
  13.710 +	LineParser::EvalEor()
  13.711 +*/
  13.712 +/*************************************************************************************************/
  13.713 +void LineParser::EvalEor()
  13.714 +{
  13.715 +	if ( m_valueStackPtr < 2 )
  13.716 +	{
  13.717 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.718 +	}
  13.719 +	m_valueStack[ m_valueStackPtr - 2 ] = static_cast< double >(
  13.720 +		static_cast< int >( m_valueStack[ m_valueStackPtr - 2 ] ) ^
  13.721 +		static_cast< int >( m_valueStack[ m_valueStackPtr - 1 ] ) );
  13.722 +	m_valueStackPtr--;
  13.723 +}
  13.724 +
  13.725 +
  13.726 +
  13.727 +/*************************************************************************************************/
  13.728 +/**
  13.729 +	LineParser::EvalEqual()
  13.730 +*/
  13.731 +/*************************************************************************************************/
  13.732 +void LineParser::EvalEqual()
  13.733 +{
  13.734 +	if ( m_valueStackPtr < 2 )
  13.735 +	{
  13.736 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.737 +	}
  13.738 +	m_valueStack[ m_valueStackPtr - 2 ] = -( m_valueStack[ m_valueStackPtr - 2 ] == m_valueStack[ m_valueStackPtr - 1 ] );
  13.739 +	m_valueStackPtr--;
  13.740 +}
  13.741 +
  13.742 +
  13.743 +
  13.744 +/*************************************************************************************************/
  13.745 +/**
  13.746 +	LineParser::EvalNotEqual()
  13.747 +*/
  13.748 +/*************************************************************************************************/
  13.749 +void LineParser::EvalNotEqual()
  13.750 +{
  13.751 +	if ( m_valueStackPtr < 2 )
  13.752 +	{
  13.753 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.754 +	}
  13.755 +	m_valueStack[ m_valueStackPtr - 2 ] = -( m_valueStack[ m_valueStackPtr - 2 ] != m_valueStack[ m_valueStackPtr - 1 ] );
  13.756 +	m_valueStackPtr--;
  13.757 +}
  13.758 +
  13.759 +
  13.760 +
  13.761 +/*************************************************************************************************/
  13.762 +/**
  13.763 +	LineParser::EvalLessThanOrEqual()
  13.764 +*/
  13.765 +/*************************************************************************************************/
  13.766 +void LineParser::EvalLessThanOrEqual()
  13.767 +{
  13.768 +	if ( m_valueStackPtr < 2 )
  13.769 +	{
  13.770 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.771 +	}
  13.772 +	m_valueStack[ m_valueStackPtr - 2 ] = -( m_valueStack[ m_valueStackPtr - 2 ] <= m_valueStack[ m_valueStackPtr - 1 ] );
  13.773 +	m_valueStackPtr--;
  13.774 +}
  13.775 +
  13.776 +
  13.777 +
  13.778 +/*************************************************************************************************/
  13.779 +/**
  13.780 +	LineParser::EvalMoreThanOrEqual()
  13.781 +*/
  13.782 +/*************************************************************************************************/
  13.783 +void LineParser::EvalMoreThanOrEqual()
  13.784 +{
  13.785 +	if ( m_valueStackPtr < 2 )
  13.786 +	{
  13.787 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.788 +	}
  13.789 +	m_valueStack[ m_valueStackPtr - 2 ] = -( m_valueStack[ m_valueStackPtr - 2 ] >= m_valueStack[ m_valueStackPtr - 1 ] );
  13.790 +	m_valueStackPtr--;
  13.791 +}
  13.792 +
  13.793 +
  13.794 +
  13.795 +/*************************************************************************************************/
  13.796 +/**
  13.797 +	LineParser::EvalLessThan()
  13.798 +*/
  13.799 +/*************************************************************************************************/
  13.800 +void LineParser::EvalLessThan()
  13.801 +{
  13.802 +	if ( m_valueStackPtr < 2 )
  13.803 +	{
  13.804 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.805 +	}
  13.806 +	m_valueStack[ m_valueStackPtr - 2 ] = -( m_valueStack[ m_valueStackPtr - 2 ] < m_valueStack[ m_valueStackPtr - 1 ] );
  13.807 +	m_valueStackPtr--;
  13.808 +}
  13.809 +
  13.810 +
  13.811 +
  13.812 +/*************************************************************************************************/
  13.813 +/**
  13.814 +	LineParser::EvalMoreThan()
  13.815 +*/
  13.816 +/*************************************************************************************************/
  13.817 +void LineParser::EvalMoreThan()
  13.818 +{
  13.819 +	if ( m_valueStackPtr < 2 )
  13.820 +	{
  13.821 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.822 +	}
  13.823 +	m_valueStack[ m_valueStackPtr - 2 ] = -( m_valueStack[ m_valueStackPtr - 2 ] > m_valueStack[ m_valueStackPtr - 1 ] );
  13.824 +	m_valueStackPtr--;
  13.825 +}
  13.826 +
  13.827 +
  13.828 +
  13.829 +/*************************************************************************************************/
  13.830 +/**
  13.831 +	LineParser::EvalNegate()
  13.832 +*/
  13.833 +/*************************************************************************************************/
  13.834 +void LineParser::EvalNegate()
  13.835 +{
  13.836 +	if ( m_valueStackPtr < 1 )
  13.837 +	{
  13.838 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.839 +	}
  13.840 +	m_valueStack[ m_valueStackPtr - 1 ] = -m_valueStack[ m_valueStackPtr - 1 ];
  13.841 +}
  13.842 +
  13.843 +
  13.844 +
  13.845 +/*************************************************************************************************/
  13.846 +/**
  13.847 +	LineParser::EvalPosate()
  13.848 +*/
  13.849 +/*************************************************************************************************/
  13.850 +void LineParser::EvalPosate()
  13.851 +{
  13.852 +	if ( m_valueStackPtr < 1 )
  13.853 +	{
  13.854 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.855 +	}
  13.856 +	// does absolutely nothing
  13.857 +}
  13.858 +
  13.859 +
  13.860 +
  13.861 +/*************************************************************************************************/
  13.862 +/**
  13.863 +	LineParser::EvalLo()
  13.864 +*/
  13.865 +/*************************************************************************************************/
  13.866 +void LineParser::EvalLo()
  13.867 +{
  13.868 +	if ( m_valueStackPtr < 1 )
  13.869 +	{
  13.870 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.871 +	}
  13.872 +	m_valueStack[ m_valueStackPtr - 1 ] = static_cast< double >(
  13.873 +		static_cast< int >( m_valueStack[ m_valueStackPtr - 1 ] ) & 0xFF );
  13.874 +}
  13.875 +
  13.876 +
  13.877 +
  13.878 +/*************************************************************************************************/
  13.879 +/**
  13.880 +	LineParser::EvalHi()
  13.881 +*/
  13.882 +/*************************************************************************************************/
  13.883 +void LineParser::EvalHi()
  13.884 +{
  13.885 +	if ( m_valueStackPtr < 1 )
  13.886 +	{
  13.887 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.888 +	}
  13.889 +	m_valueStack[ m_valueStackPtr - 1 ] = static_cast< double >(
  13.890 +		( static_cast< int >( m_valueStack[ m_valueStackPtr - 1 ] ) & 0xffff ) >> 8 );
  13.891 +}
  13.892 +
  13.893 +
  13.894 +
  13.895 +/*************************************************************************************************/
  13.896 +/**
  13.897 +	LineParser::EvalSin()
  13.898 +*/
  13.899 +/*************************************************************************************************/
  13.900 +void LineParser::EvalSin()
  13.901 +{
  13.902 +	if ( m_valueStackPtr < 1 )
  13.903 +	{
  13.904 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.905 +	}
  13.906 +	m_valueStack[ m_valueStackPtr - 1 ] = sin( m_valueStack[ m_valueStackPtr - 1 ] );
  13.907 +}
  13.908 +
  13.909 +
  13.910 +
  13.911 +/*************************************************************************************************/
  13.912 +/**
  13.913 +	LineParser::EvalCos()
  13.914 +*/
  13.915 +/*************************************************************************************************/
  13.916 +void LineParser::EvalCos()
  13.917 +{
  13.918 +	if ( m_valueStackPtr < 1 )
  13.919 +	{
  13.920 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.921 +	}
  13.922 +	m_valueStack[ m_valueStackPtr - 1 ] = cos( m_valueStack[ m_valueStackPtr - 1 ] );
  13.923 +}
  13.924 +
  13.925 +
  13.926 +
  13.927 +/*************************************************************************************************/
  13.928 +/**
  13.929 +	LineParser::EvalTan()
  13.930 +*/
  13.931 +/*************************************************************************************************/
  13.932 +void LineParser::EvalTan()
  13.933 +{
  13.934 +	if ( m_valueStackPtr < 1 )
  13.935 +	{
  13.936 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.937 +	}
  13.938 +	m_valueStack[ m_valueStackPtr - 1 ] = tan( m_valueStack[ m_valueStackPtr - 1 ] );
  13.939 +}
  13.940 +
  13.941 +
  13.942 +
  13.943 +/*************************************************************************************************/
  13.944 +/**
  13.945 +	LineParser::EvalArcSin()
  13.946 +*/
  13.947 +/*************************************************************************************************/
  13.948 +void LineParser::EvalArcSin()
  13.949 +{
  13.950 +	if ( m_valueStackPtr < 1 )
  13.951 +	{
  13.952 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.953 +	}
  13.954 +	m_valueStack[ m_valueStackPtr - 1 ] = asin( m_valueStack[ m_valueStackPtr - 1 ] );
  13.955 +
  13.956 +	if ( errno == EDOM )
  13.957 +	{
  13.958 +		throw AsmException_SyntaxError_IllegalOperation( m_line, m_column - 1 );
  13.959 +	}
  13.960 +}
  13.961 +
  13.962 +
  13.963 +
  13.964 +/*************************************************************************************************/
  13.965 +/**
  13.966 +	LineParser::EvalArcCos()
  13.967 +*/
  13.968 +/*************************************************************************************************/
  13.969 +void LineParser::EvalArcCos()
  13.970 +{
  13.971 +	if ( m_valueStackPtr < 1 )
  13.972 +	{
  13.973 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.974 +	}
  13.975 +	m_valueStack[ m_valueStackPtr - 1 ] = acos( m_valueStack[ m_valueStackPtr - 1 ] );
  13.976 +
  13.977 +	if ( errno == EDOM )
  13.978 +	{
  13.979 +		throw AsmException_SyntaxError_IllegalOperation( m_line, m_column - 1 );
  13.980 +	}
  13.981 +}
  13.982 +
  13.983 +
  13.984 +
  13.985 +/*************************************************************************************************/
  13.986 +/**
  13.987 +	LineParser::EvalArcTan()
  13.988 +*/
  13.989 +/*************************************************************************************************/
  13.990 +void LineParser::EvalArcTan()
  13.991 +{
  13.992 +	if ( m_valueStackPtr < 1 )
  13.993 +	{
  13.994 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
  13.995 +	}
  13.996 +	m_valueStack[ m_valueStackPtr - 1 ] = atan( m_valueStack[ m_valueStackPtr - 1 ] );
  13.997 +
  13.998 +	if ( errno == EDOM )
  13.999 +	{
 13.1000 +		throw AsmException_SyntaxError_IllegalOperation( m_line, m_column - 1 );
 13.1001 +	}
 13.1002 +}
 13.1003 +
 13.1004 +
 13.1005 +
 13.1006 +/*************************************************************************************************/
 13.1007 +/**
 13.1008 +	LineParser::EvalSqrt()
 13.1009 +*/
 13.1010 +/*************************************************************************************************/
 13.1011 +void LineParser::EvalSqrt()
 13.1012 +{
 13.1013 +	if ( m_valueStackPtr < 1 )
 13.1014 +	{
 13.1015 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
 13.1016 +	}
 13.1017 +	m_valueStack[ m_valueStackPtr - 1 ] = sqrt( m_valueStack[ m_valueStackPtr - 1 ] );
 13.1018 +
 13.1019 +	if ( errno == EDOM )
 13.1020 +	{
 13.1021 +		throw AsmException_SyntaxError_IllegalOperation( m_line, m_column - 1 );
 13.1022 +	}
 13.1023 +}
 13.1024 +
 13.1025 +
 13.1026 +
 13.1027 +/*************************************************************************************************/
 13.1028 +/**
 13.1029 +	LineParser::EvalDegToRad()
 13.1030 +*/
 13.1031 +/*************************************************************************************************/
 13.1032 +void LineParser::EvalDegToRad()
 13.1033 +{
 13.1034 +	if ( m_valueStackPtr < 1 )
 13.1035 +	{
 13.1036 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
 13.1037 +	}
 13.1038 +	m_valueStack[ m_valueStackPtr - 1 ] = m_valueStack[ m_valueStackPtr - 1 ] * M_PI / 180.0;
 13.1039 +}
 13.1040 +
 13.1041 +
 13.1042 +
 13.1043 +/*************************************************************************************************/
 13.1044 +/**
 13.1045 +	LineParser::EvalRadToDeg()
 13.1046 +*/
 13.1047 +/*************************************************************************************************/
 13.1048 +void LineParser::EvalRadToDeg()
 13.1049 +{
 13.1050 +	if ( m_valueStackPtr < 1 )
 13.1051 +	{
 13.1052 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
 13.1053 +	}
 13.1054 +	m_valueStack[ m_valueStackPtr - 1 ] = m_valueStack[ m_valueStackPtr - 1 ] * 180.0 / M_PI;
 13.1055 +}
 13.1056 +
 13.1057 +
 13.1058 +
 13.1059 +/*************************************************************************************************/
 13.1060 +/**
 13.1061 +	LineParser::EvalInt()
 13.1062 +*/
 13.1063 +/*************************************************************************************************/
 13.1064 +void LineParser::EvalInt()
 13.1065 +{
 13.1066 +	if ( m_valueStackPtr < 1 )
 13.1067 +	{
 13.1068 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
 13.1069 +	}
 13.1070 +	m_valueStack[ m_valueStackPtr - 1 ] = static_cast< double >(
 13.1071 +		static_cast< int >( m_valueStack[ m_valueStackPtr - 1 ] ) );
 13.1072 +}
 13.1073 +
 13.1074 +
 13.1075 +
 13.1076 +/*************************************************************************************************/
 13.1077 +/**
 13.1078 +	LineParser::EvalAbs()
 13.1079 +*/
 13.1080 +/*************************************************************************************************/
 13.1081 +void LineParser::EvalAbs()
 13.1082 +{
 13.1083 +	if ( m_valueStackPtr < 1 )
 13.1084 +	{
 13.1085 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
 13.1086 +	}
 13.1087 +	m_valueStack[ m_valueStackPtr - 1 ] = abs( m_valueStack[ m_valueStackPtr - 1 ] );
 13.1088 +}
 13.1089 +
 13.1090 +
 13.1091 +
 13.1092 +/*************************************************************************************************/
 13.1093 +/**
 13.1094 +	LineParser::EvalSgn()
 13.1095 +*/
 13.1096 +/*************************************************************************************************/
 13.1097 +void LineParser::EvalSgn()
 13.1098 +{
 13.1099 +	if ( m_valueStackPtr < 1 )
 13.1100 +	{
 13.1101 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
 13.1102 +	}
 13.1103 +
 13.1104 +	double val = m_valueStack[ m_valueStackPtr - 1 ];
 13.1105 +	m_valueStack[ m_valueStackPtr - 1 ] = ( val < 0.0 ) ? -1.0 : ( ( val > 0.0 ) ? 1.0 : 0.0 );
 13.1106 +}
 13.1107 +
 13.1108 +
 13.1109 +
 13.1110 +/*************************************************************************************************/
 13.1111 +/**
 13.1112 +	LineParser::EvalRnd()
 13.1113 +*/
 13.1114 +/*************************************************************************************************/
 13.1115 +void LineParser::EvalRnd()
 13.1116 +{
 13.1117 +	if ( m_valueStackPtr < 1 )
 13.1118 +	{
 13.1119 +		throw AsmException_SyntaxError_MissingValue( m_line, m_column );
 13.1120 +	}
 13.1121 +
 13.1122 +	double val = m_valueStack[ m_valueStackPtr - 1 ];
 13.1123 +	double result = 0.0;
 13.1124 +
 13.1125 +	if ( val < 1.0f )
 13.1126 +	{
 13.1127 +		throw AsmException_SyntaxError_IllegalOperation( m_line, m_column - 1 );
 13.1128 +	}
 13.1129 +	else if ( val == 1.0f )
 13.1130 +	{
 13.1131 +		result = rand() / ( static_cast< double >( RAND_MAX ) + 1.0 );
 13.1132 +	}
 13.1133 +	else
 13.1134 +	{
 13.1135 +		result = static_cast< double >( static_cast< int >( rand() / ( static_cast< double >( RAND_MAX ) + 1.0 ) * val ) );
 13.1136 +	}
 13.1137 +
 13.1138 +	m_valueStack[ m_valueStackPtr - 1 ] = result;
 13.1139 +}
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/src/globaldata.cpp	Sat May 01 19:35:42 2010 +0100
    14.3 @@ -0,0 +1,72 @@
    14.4 +/*************************************************************************************************/
    14.5 +/**
    14.6 +	globaldata.cpp
    14.7 +*/
    14.8 +/*************************************************************************************************/
    14.9 +
   14.10 +#include "globaldata.h"
   14.11 +
   14.12 +GlobalData* GlobalData::m_gInstance = NULL;
   14.13 +
   14.14 +
   14.15 +
   14.16 +/*************************************************************************************************/
   14.17 +/**
   14.18 +	GlobalData::Create()
   14.19 +
   14.20 +	Creates the GlobalData singleton
   14.21 +*/
   14.22 +/*************************************************************************************************/
   14.23 +void GlobalData::Create()
   14.24 +{
   14.25 +	assert( m_gInstance == NULL );
   14.26 +
   14.27 +	m_gInstance = new GlobalData;
   14.28 +}
   14.29 +
   14.30 +
   14.31 +
   14.32 +/*************************************************************************************************/
   14.33 +/**
   14.34 +	GlobalData::Destroy()
   14.35 +
   14.36 +	Destroys the GlobalData singleton
   14.37 +*/
   14.38 +/*************************************************************************************************/
   14.39 +void GlobalData::Destroy()
   14.40 +{
   14.41 +	assert( m_gInstance != NULL );
   14.42 +
   14.43 +	delete m_gInstance;
   14.44 +	m_gInstance = NULL;
   14.45 +}
   14.46 +
   14.47 +
   14.48 +
   14.49 +/*************************************************************************************************/
   14.50 +/**
   14.51 +	GlobalData::GlobalData()
   14.52 +
   14.53 +	GlobalData constructor
   14.54 +*/
   14.55 +/*************************************************************************************************/
   14.56 +GlobalData::GlobalData()
   14.57 +	:	m_pBootFile( NULL ),
   14.58 +		m_bVerbose( false ),
   14.59 +		m_bUseDiscImage( false ),
   14.60 +		m_pDiscImage( NULL )
   14.61 +{
   14.62 +}
   14.63 +
   14.64 +
   14.65 +
   14.66 +/*************************************************************************************************/
   14.67 +/**
   14.68 +	GlobalData::~GlobalData()
   14.69 +
   14.70 +	GlobalData destructor
   14.71 +*/
   14.72 +/*************************************************************************************************/
   14.73 +GlobalData::~GlobalData()
   14.74 +{
   14.75 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/src/globaldata.h	Sat May 01 19:35:42 2010 +0100
    15.3 @@ -0,0 +1,59 @@
    15.4 +/*************************************************************************************************/
    15.5 +/**
    15.6 +	globaldata.h
    15.7 +*/
    15.8 +/*************************************************************************************************/
    15.9 +
   15.10 +#ifndef GLOBALDATA_H_
   15.11 +#define GLOBALDATA_H_
   15.12 +
   15.13 +#include <cassert>
   15.14 +#include <cstdlib>
   15.15 +
   15.16 +
   15.17 +class DiscImage;
   15.18 +
   15.19 +class GlobalData
   15.20 +{
   15.21 +public:
   15.22 +
   15.23 +	static void Create();
   15.24 +	static void Destroy();
   15.25 +	static inline GlobalData& Instance() { assert( m_gInstance != NULL ); return *m_gInstance; }
   15.26 +
   15.27 +	inline void SetPass( int i )				{ m_pass = i; }
   15.28 +	inline void SetBootFile( const char* p )	{ m_pBootFile = p; }
   15.29 +	inline void SetVerbose( bool b )			{ m_bVerbose = b; }
   15.30 +	inline void SetUseDiscImage( bool b )		{ m_bUseDiscImage = b; }
   15.31 +	inline void SetDiscImage( DiscImage* d )	{ m_pDiscImage = d; }
   15.32 +	inline void ResetForId()					{ m_forId = 0; }
   15.33 +
   15.34 +	inline int GetPass() const					{ return m_pass; }
   15.35 +	inline bool IsFirstPass() const				{ return ( m_pass == 0 ); }
   15.36 +	inline bool IsSecondPass() const			{ return ( m_pass == 1 ); }
   15.37 +	inline bool ShouldOutputAsm() const			{ return ( m_pass == 1 && m_bVerbose ); }
   15.38 +	inline const char* GetBootFile() const		{ return m_pBootFile; }
   15.39 +	inline bool UsesDiscImage() const			{ return m_bUseDiscImage; }
   15.40 +	inline DiscImage* GetDiscImage() const		{ return m_pDiscImage; }
   15.41 +	inline int GetNextForId()					{ return m_forId++; }
   15.42 +
   15.43 +
   15.44 +private:
   15.45 +
   15.46 +	GlobalData();
   15.47 +	~GlobalData();
   15.48 +
   15.49 +	static GlobalData*			m_gInstance;
   15.50 +
   15.51 +	int							m_pass;
   15.52 +	const char*					m_pBootFile;
   15.53 +	bool						m_bVerbose;
   15.54 +	bool						m_bUseDiscImage;
   15.55 +	DiscImage*					m_pDiscImage;
   15.56 +	int							m_forId;
   15.57 +	int							m_randomSeed;
   15.58 +};
   15.59 +
   15.60 +
   15.61 +
   15.62 +#endif // GLOBALDATA_H_
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/src/lineparser.cpp	Sat May 01 19:35:42 2010 +0100
    16.3 @@ -0,0 +1,352 @@
    16.4 +/*************************************************************************************************/
    16.5 +/**
    16.6 +	lineparser.cpp
    16.7 +
    16.8 +	Represents a line of the source file
    16.9 +*/
   16.10 +/*************************************************************************************************/
   16.11 +
   16.12 +#include "lineparser.h"
   16.13 +#include "asmexception.h"
   16.14 +#include "stringutils.h"
   16.15 +#include "symboltable.h"
   16.16 +#include "globaldata.h"
   16.17 +#include "sourcefile.h"
   16.18 +
   16.19 +
   16.20 +using namespace std;
   16.21 +
   16.22 +
   16.23 +
   16.24 +/*************************************************************************************************/
   16.25 +/**
   16.26 +	LineParser::LineParser()
   16.27 +
   16.28 +	Constructor for LineParser
   16.29 +*/
   16.30 +/*************************************************************************************************/
   16.31 +LineParser::LineParser( SourceFile* sourceFile, string line )
   16.32 +	:	m_sourceFile( sourceFile ),
   16.33 +		m_line( line ),
   16.34 +		m_column( 0 )
   16.35 +{
   16.36 +}
   16.37 +
   16.38 +
   16.39 +
   16.40 +/*************************************************************************************************/
   16.41 +/**
   16.42 +	LineParser::~LineParser()
   16.43 +
   16.44 +	Destructor for LineParser
   16.45 +*/
   16.46 +/*************************************************************************************************/
   16.47 +LineParser::~LineParser()
   16.48 +{
   16.49 +}
   16.50 +
   16.51 +
   16.52 +
   16.53 +/*************************************************************************************************/
   16.54 +/**
   16.55 +	LineParser::ProcessLine()
   16.56 +
   16.57 +	Process one line of the file
   16.58 +*/
   16.59 +/*************************************************************************************************/
   16.60 +void LineParser::Process()
   16.61 +{
   16.62 +	while ( AdvanceAndCheckEndOfLine() )	// keep going until we reach the end of the line
   16.63 +	{
   16.64 +//		cout << m_line << endl << string( m_column, ' ' ) << "^" << endl;
   16.65 +
   16.66 +		int oldColumn = m_column;
   16.67 +
   16.68 +		// first check tokens - they have priority over opcodes, so that they can have names
   16.69 +		// like INCLUDE (which would otherwise be interpreted as INC LUDE)
   16.70 +
   16.71 +		int token = GetTokenAndAdvanceColumn();
   16.72 +
   16.73 +		if ( token != -1 )
   16.74 +		{
   16.75 +			HandleToken( token, oldColumn );
   16.76 +			continue;
   16.77 +		}
   16.78 +
   16.79 +		// Next we see if we should even be trying to execute anything.... maybe the if condition is false
   16.80 +
   16.81 +		if ( !m_sourceFile->IsIfConditionTrue() )
   16.82 +		{
   16.83 +			m_column = oldColumn;
   16.84 +			SkipStatement();
   16.85 +			continue;
   16.86 +		}
   16.87 +
   16.88 +		// No token match - check against opcodes
   16.89 +
   16.90 +		token = GetInstructionAndAdvanceColumn();
   16.91 +
   16.92 +		if ( token != -1 )
   16.93 +		{
   16.94 +			HandleAssembler( token );
   16.95 +			continue;
   16.96 +		}
   16.97 +
   16.98 +		// Check to see if it's symbol assignment
   16.99 +
  16.100 +		if ( !isalpha( m_line[ m_column ] ) && m_line[ m_column ] != '_' )
  16.101 +		{
  16.102 +			throw AsmException_SyntaxError_UnrecognisedToken( m_line, m_column );
  16.103 +		}
  16.104 +
  16.105 +		// Must be symbol assignment
  16.106 +
  16.107 +		// Symbol starts with a valid character
  16.108 +
  16.109 +		string symbolName = GetSymbolName() + m_sourceFile->GetSymbolNameSuffix();
  16.110 +
  16.111 +		if ( !AdvanceAndCheckEndOfStatement() )
  16.112 +		{
  16.113 +			throw AsmException_SyntaxError_UnrecognisedToken( m_line, oldColumn );
  16.114 +		}
  16.115 +
  16.116 +		if ( m_line[ m_column ] != '=' )
  16.117 +		{
  16.118 +			throw AsmException_SyntaxError_UnrecognisedToken( m_line, oldColumn );
  16.119 +		}
  16.120 +
  16.121 +		m_column++;
  16.122 +
  16.123 +		double value = EvaluateExpression();
  16.124 +
  16.125 +		if ( GlobalData::Instance().IsFirstPass() )
  16.126 +		{
  16.127 +			// only add the symbol on the first pass
  16.128 +
  16.129 +			if ( SymbolTable::Instance().IsSymbolDefined( symbolName ) )
  16.130 +			{
  16.131 +				throw AsmException_SyntaxError_LabelAlreadyDefined( m_line, oldColumn );
  16.132 +			}
  16.133 +			else
  16.134 +			{
  16.135 +				SymbolTable::Instance().AddSymbol( symbolName, value );
  16.136 +			}
  16.137 +		}
  16.138 +
  16.139 +		if ( m_line[ m_column ] == ',' )
  16.140 +		{
  16.141 +			// Unexpected comma (remembering that an expression can validly end with a comma)
  16.142 +			throw AsmException_SyntaxError_UnexpectedComma( m_line, m_column );
  16.143 +		}
  16.144 +
  16.145 +	}
  16.146 +}
  16.147 +
  16.148 +
  16.149 +
  16.150 +/*************************************************************************************************/
  16.151 +/**
  16.152 +	LineParser::SkipStatement()
  16.153 +
  16.154 +	Moves past the current statement to the next
  16.155 +*/
  16.156 +/*************************************************************************************************/
  16.157 +void LineParser::SkipStatement()
  16.158 +{
  16.159 +	bool bInQuotes = false;
  16.160 +	bool bInSingleQuotes = false;
  16.161 +
  16.162 +	while ( m_column < m_line.length() && ( bInQuotes || bInSingleQuotes || MoveToNextAtom( ":;\\" ) ) )
  16.163 +	{
  16.164 +		if ( m_line[ m_column ] == '\"' && !bInSingleQuotes )
  16.165 +		{
  16.166 +			bInQuotes = !bInQuotes;
  16.167 +		}
  16.168 +		else if ( m_line[ m_column ] == '\'' )
  16.169 +		{
  16.170 +			if ( bInSingleQuotes )
  16.171 +			{
  16.172 +				bInSingleQuotes = false;
  16.173 +			}
  16.174 +			else if ( m_line[ m_column + 2 ] == '\'' && !bInQuotes )
  16.175 +			{
  16.176 +				bInSingleQuotes = true;
  16.177 +				m_column++;
  16.178 +			}
  16.179 +		}
  16.180 +
  16.181 +		m_column++;
  16.182 +	}
  16.183 +
  16.184 +	if ( m_line[ m_column ] == '\\' || m_line[ m_column ] == ';' )
  16.185 +	{
  16.186 +		m_column = m_line.length();
  16.187 +	}
  16.188 +	else if ( m_line[ m_column ] == ':' )
  16.189 +	{
  16.190 +		m_column++;
  16.191 +	}
  16.192 +}
  16.193 +
  16.194 +
  16.195 +
  16.196 +/*************************************************************************************************/
  16.197 +/**
  16.198 +	LineParser::HandleToken()
  16.199 +
  16.200 +	Calls the handler for the specified token
  16.201 +
  16.202 +	@param		i				Index of the token to be handled
  16.203 +*/
  16.204 +/*************************************************************************************************/
  16.205 +void LineParser::HandleToken( int i, int oldColumn )
  16.206 +{
  16.207 +	assert( i >= 0 );
  16.208 +
  16.209 +	// Do special case handling for IF/ELSE/ENDIF
  16.210 +
  16.211 +	if ( m_gaTokenTable[ i ].m_handler == &LineParser::HandleIf )
  16.212 +	{
  16.213 +		m_sourceFile->AddIfLevel( m_line, m_column );
  16.214 +	}
  16.215 +	else if ( m_gaTokenTable[ i ].m_handler == &LineParser::HandleElse )
  16.216 +	{
  16.217 +		m_sourceFile->ToggleCurrentIfCondition( m_line, m_column );
  16.218 +	}
  16.219 +	else if ( m_gaTokenTable[ i ].m_handler == &LineParser::HandleEndif )
  16.220 +	{
  16.221 +		m_sourceFile->RemoveIfLevel( m_line, m_column );
  16.222 +	}
  16.223 +
  16.224 +	if ( m_sourceFile->IsIfConditionTrue() )
  16.225 +	{
  16.226 +		( this->*m_gaTokenTable[ i ].m_handler )();
  16.227 +	}
  16.228 +	else
  16.229 +	{
  16.230 +		m_column = oldColumn;
  16.231 +		SkipStatement();
  16.232 +	}
  16.233 +}
  16.234 +
  16.235 +
  16.236 +
  16.237 +/*************************************************************************************************/
  16.238 +/**
  16.239 +	LineParser::MoveToNextAtom()
  16.240 +
  16.241 +	Moves the line pointer to the next significant atom to be parsed
  16.242 +
  16.243 +	@return		bool		false if we reached a terminator
  16.244 +							true if the pointer is at a valid atom
  16.245 +*/
  16.246 +/*************************************************************************************************/
  16.247 +bool LineParser::MoveToNextAtom( const char* pTerminators )
  16.248 +{
  16.249 +	if ( !StringUtils::EatWhitespace( m_line, m_column ) )
  16.250 +	{
  16.251 +		return false;
  16.252 +	}
  16.253 +
  16.254 +	if ( pTerminators != NULL )
  16.255 +	{
  16.256 +		size_t i = 0;
  16.257 +
  16.258 +		while ( pTerminators[ i ] != 0 )
  16.259 +		{
  16.260 +			if ( m_line[ m_column ] == pTerminators[ i ] )
  16.261 +			{
  16.262 +				return false;
  16.263 +			}
  16.264 +
  16.265 +			i++;
  16.266 +		}
  16.267 +	}
  16.268 +
  16.269 +	return true;
  16.270 +}
  16.271 +
  16.272 +
  16.273 +
  16.274 +/*************************************************************************************************/
  16.275 +/**
  16.276 +	LineParser::AdvanceAndCheckEndOfLine()
  16.277 +
  16.278 +	Moves the line pointer to the next significant atom to be parsed, and checks whether the end
  16.279 +	of the line has been reached
  16.280 +
  16.281 +	@return		bool		true if we are not yet at the end of the line
  16.282 +*/
  16.283 +/*************************************************************************************************/
  16.284 +bool LineParser::AdvanceAndCheckEndOfLine()
  16.285 +{
  16.286 +	return MoveToNextAtom();
  16.287 +}
  16.288 +
  16.289 +
  16.290 +
  16.291 +/*************************************************************************************************/
  16.292 +/**
  16.293 +	LineParser::AdvanceAndCheckEndOfStatement()
  16.294 +
  16.295 +	Moves the line pointer to the next significant atom to be parsed, and checks whether the end
  16.296 +	of the current statement has been reached.
  16.297 +
  16.298 +	Valid statement terminators are the end of the line, a semicolon or backslash (comment), or
  16.299 +	a colon (statement separator)
  16.300 +
  16.301 +	@return		bool		true if we are not yet at the end of the statement
  16.302 +*/
  16.303 +/*************************************************************************************************/
  16.304 +bool LineParser::AdvanceAndCheckEndOfStatement()
  16.305 +{
  16.306 +	return MoveToNextAtom( ";:\\" );
  16.307 +}
  16.308 +
  16.309 +
  16.310 +
  16.311 +/*************************************************************************************************/
  16.312 +/**
  16.313 +	LineParser::AdvanceAndCheckEndOfSubStatement()
  16.314 +
  16.315 +	Moves the line pointer to the next significant atom to be parsed, and checks whether the end
  16.316 +	of the current substatement has been reached.
  16.317 +
  16.318 +	Valid substatement terminators are the end of the line, a semicolon or backslash (comment), a
  16.319 +	comma (substatement separator), or a colon (statement separator)
  16.320 +
  16.321 +	@return		bool		true if we are not yet at the end of the substatement
  16.322 +*/
  16.323 +/*************************************************************************************************/
  16.324 +bool LineParser::AdvanceAndCheckEndOfSubStatement()
  16.325 +{
  16.326 +	return MoveToNextAtom( ";:\\," );
  16.327 +}
  16.328 +
  16.329 +
  16.330 +
  16.331 +/*************************************************************************************************/
  16.332 +/**
  16.333 +	LineParser::GetSymbolName()
  16.334 +
  16.335 +	This returns a valid symbol name, and advances the string pointer.
  16.336 +	It is assumed that we are already pointing to a valid symbol name.
  16.337 +*/
  16.338 +/*************************************************************************************************/
  16.339 +string LineParser::GetSymbolName()
  16.340 +{
  16.341 +	assert( isalpha( m_line[ m_column ] ) || m_line[ m_column ] == '_' );
  16.342 +
  16.343 +	string symbolName;
  16.344 +
  16.345 +	do
  16.346 +	{
  16.347 +		symbolName += m_line[ m_column++ ];
  16.348 +
  16.349 +	} while ( isalpha( m_line[ m_column ] ) ||
  16.350 +			  isdigit( m_line[ m_column ] ) ||
  16.351 +			  m_line[ m_column ] == '_' ||
  16.352 +			  m_line[ m_column ] == '%' );
  16.353 +
  16.354 +	return symbolName;
  16.355 +}
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/src/lineparser.h	Sat May 01 19:35:42 2010 +0100
    17.3 @@ -0,0 +1,187 @@
    17.4 +/*************************************************************************************************/
    17.5 +/**
    17.6 +	lineparser.h
    17.7 +*/
    17.8 +/*************************************************************************************************/
    17.9 +
   17.10 +#ifndef LINEPARSER_H_
   17.11 +#define LINEPARSER_H_
   17.12 +
   17.13 +#include <string>
   17.14 +
   17.15 +class SourceFile;
   17.16 +
   17.17 +class LineParser
   17.18 +{
   17.19 +public:
   17.20 +
   17.21 +	// Constructor/destructor
   17.22 +
   17.23 +	LineParser( SourceFile* sourceFile, std::string line );
   17.24 +	~LineParser();
   17.25 +
   17.26 +	// Process the line
   17.27 +
   17.28 +	void Process();
   17.29 +
   17.30 +	// Accessors
   17.31 +
   17.32 +
   17.33 +private:
   17.34 +
   17.35 +	typedef void ( LineParser::*TokenHandler )();
   17.36 +
   17.37 +	struct Token
   17.38 +	{
   17.39 +		const char*		m_pName;
   17.40 +		TokenHandler	m_handler;
   17.41 +	};
   17.42 +
   17.43 +	enum ADDRESSING_MODE
   17.44 +	{
   17.45 +		IMP,
   17.46 +		ACC,
   17.47 +		IMM,
   17.48 +		ZP,
   17.49 +		ZPX,
   17.50 +		ZPY,
   17.51 +		ABS,
   17.52 +		ABSX,
   17.53 +		ABSY,
   17.54 +		INDX,
   17.55 +		INDY,
   17.56 +		IND16,
   17.57 +		REL,
   17.58 +
   17.59 +		NUM_ADDRESSING_MODES
   17.60 +	};
   17.61 +
   17.62 +	struct OpcodeData
   17.63 +	{
   17.64 +		short			m_aOpcodes[NUM_ADDRESSING_MODES];
   17.65 +		const char*		m_pName;
   17.66 +	};
   17.67 +
   17.68 +
   17.69 +	typedef void ( LineParser::*OperatorHandler )();
   17.70 +
   17.71 +	struct Operator
   17.72 +	{
   17.73 +		const char*			token;
   17.74 +		int					precedence;
   17.75 +		OperatorHandler		handler;
   17.76 +	};
   17.77 +
   17.78 +	enum TYPE
   17.79 +	{
   17.80 +		VALUE_OR_UNARY,
   17.81 +		BINARY
   17.82 +	};
   17.83 +
   17.84 +
   17.85 +	// line parsing methods
   17.86 +
   17.87 +	int				GetTokenAndAdvanceColumn();
   17.88 +	void			HandleToken( int i, int oldColumn );
   17.89 +	int				GetInstructionAndAdvanceColumn();
   17.90 +	bool			MoveToNextAtom( const char* pTerminators = NULL );
   17.91 +	bool			AdvanceAndCheckEndOfLine();
   17.92 +	bool			AdvanceAndCheckEndOfStatement();
   17.93 +	bool			AdvanceAndCheckEndOfSubStatement();
   17.94 +	void			SkipStatement();
   17.95 +	std::string		GetSymbolName();
   17.96 +
   17.97 +	// assembler generating methods
   17.98 +
   17.99 +	void			HandleAssembler( int tokenNumber );
  17.100 +	bool			HasAddressingMode( int opcodeIndex, ADDRESSING_MODE mode );
  17.101 +	unsigned int	GetOpcode( int opcodeIndex, ADDRESSING_MODE mode );
  17.102 +	void			Assemble1( int instructionIndex, ADDRESSING_MODE mode );
  17.103 +	void			Assemble2( int instructionIndex, ADDRESSING_MODE mode, unsigned int value );
  17.104 +	void			Assemble3( int instructionIndex, ADDRESSING_MODE mode, unsigned int value );
  17.105 +
  17.106 +	// language handling methods
  17.107 +
  17.108 +	void			HandleDefineLabel();
  17.109 +	void			HandleDefineComment();
  17.110 +	void			HandleStatementSeparator();
  17.111 +	void			HandlePrint();
  17.112 +	void			HandleOrg();
  17.113 +	void			HandleInclude();
  17.114 +	void			HandleEqub();
  17.115 +	void			HandleEquw();
  17.116 +	void			HandleSave();
  17.117 +	void			HandleFor();
  17.118 +	void			HandleNext();
  17.119 +	void			HandleIf();
  17.120 +	void			HandleElse();
  17.121 +	void			HandleEndif();
  17.122 +	void			HandleAlign();
  17.123 +	void			HandleSkip();
  17.124 +	void			HandleGuard();
  17.125 +	void			HandleClear();
  17.126 +
  17.127 +	// expression evaluating methods
  17.128 +
  17.129 +	double			EvaluateExpression( bool bAllowOneMismatchedCloseBracket = false );
  17.130 +	int				EvaluateExpressionAsInt( bool bAllowOneMismatchedCloseBracket = false );
  17.131 +	double			GetValue();
  17.132 +
  17.133 +	void			EvalAdd();
  17.134 +	void			EvalSubtract();
  17.135 +	void			EvalMultiply();
  17.136 +	void			EvalDivide();
  17.137 +	void			EvalPower();
  17.138 +	void			EvalDiv();
  17.139 +	void			EvalMod();
  17.140 +	void			EvalShiftLeft();
  17.141 +	void			EvalShiftRight();
  17.142 +	void			EvalAnd();
  17.143 +	void			EvalOr();
  17.144 +	void			EvalEor();
  17.145 +	void			EvalEqual();
  17.146 +	void			EvalNotEqual();
  17.147 +	void			EvalLessThanOrEqual();
  17.148 +	void			EvalMoreThanOrEqual();
  17.149 +	void			EvalLessThan();
  17.150 +	void			EvalMoreThan();
  17.151 +
  17.152 +	void			EvalNegate();
  17.153 +	void			EvalPosate();
  17.154 +	void			EvalLo();
  17.155 +	void			EvalHi();
  17.156 +	void			EvalSin();
  17.157 +	void			EvalCos();
  17.158 +	void			EvalTan();
  17.159 +	void			EvalArcSin();
  17.160 +	void			EvalArcCos();
  17.161 +	void			EvalArcTan();
  17.162 +	void			EvalSqrt();
  17.163 +	void			EvalDegToRad();
  17.164 +	void			EvalRadToDeg();
  17.165 +	void			EvalInt();
  17.166 +	void			EvalAbs();
  17.167 +	void			EvalSgn();
  17.168 +	void			EvalRnd();
  17.169 +
  17.170 +
  17.171 +	SourceFile*				m_sourceFile;
  17.172 +	std::string				m_line;
  17.173 +	size_t					m_column;
  17.174 +
  17.175 +	static Token			m_gaTokenTable[];
  17.176 +	static OpcodeData		m_gaOpcodeTable[];
  17.177 +	static Operator			m_gaUnaryOperatorTable[];
  17.178 +	static Operator			m_gaBinaryOperatorTable[];
  17.179 +
  17.180 +	#define MAX_VALUES		128
  17.181 +	#define MAX_OPERATORS	32
  17.182 +
  17.183 +	double					m_valueStack[ MAX_VALUES ];
  17.184 +	Operator				m_operatorStack[ MAX_OPERATORS ];
  17.185 +	int						m_valueStackPtr;
  17.186 +	int						m_operatorStackPtr;
  17.187 +};
  17.188 +
  17.189 +
  17.190 +#endif // LINEPARSER_H_
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/src/main.cpp	Sat May 01 19:35:42 2010 +0100
    18.3 @@ -0,0 +1,203 @@
    18.4 +/*************************************************************************************************/
    18.5 +/**
    18.6 +	main.cpp
    18.7 +
    18.8 +	Main entry point for the application
    18.9 +*/
   18.10 +/*************************************************************************************************/
   18.11 +
   18.12 +#include <iostream>
   18.13 +#include <cstring>
   18.14 +#include <cstdlib>
   18.15 +#include <ctime>
   18.16 +
   18.17 +#include "main.h"
   18.18 +#include "sourcefile.h"
   18.19 +#include "asmexception.h"
   18.20 +#include "globaldata.h"
   18.21 +#include "objectcode.h"
   18.22 +#include "symboltable.h"
   18.23 +#include "discimage.h"
   18.24 +
   18.25 +
   18.26 +using namespace std;
   18.27 +
   18.28 +
   18.29 +#define VERSION "0.01"
   18.30 +
   18.31 +
   18.32 +/*************************************************************************************************/
   18.33 +/**
   18.34 +	main()
   18.35 +
   18.36 +	The main entry point for the application
   18.37 +
   18.38 +	@param		argc			Number of parameters passed
   18.39 +	@param		argv			Array of parameters
   18.40 +*/
   18.41 +/*************************************************************************************************/
   18.42 +
   18.43 +int main( int argc, char* argv[] )
   18.44 +{
   18.45 +	const char* pInputFile = NULL;
   18.46 +	const char* pDiscInputFile = NULL;
   18.47 +	const char* pDiscOutputFile = NULL;
   18.48 +
   18.49 +	enum STATES
   18.50 +	{
   18.51 +		READY,
   18.52 +		WAITING_FOR_INPUT_FILENAME,
   18.53 +		WAITING_FOR_DISC_INPUT_FILENAME,
   18.54 +		WAITING_FOR_DISC_OUTPUT_FILENAME,
   18.55 +		WAITING_FOR_BOOT_FILENAME
   18.56 +
   18.57 +	} state = READY;
   18.58 +
   18.59 +
   18.60 +	GlobalData::Create();
   18.61 +
   18.62 +	// Parse command line parameters
   18.63 +
   18.64 +	for ( int i = 1; i < argc; i++ )
   18.65 +	{
   18.66 +		switch ( state )
   18.67 +		{
   18.68 +			case READY:
   18.69 +
   18.70 +				if ( strcmp( argv[i], "-i" ) == 0 )
   18.71 +				{
   18.72 +					state = WAITING_FOR_INPUT_FILENAME;
   18.73 +				}
   18.74 +				else if ( strcmp( argv[i], "-do" ) == 0 )
   18.75 +				{
   18.76 +					state = WAITING_FOR_DISC_OUTPUT_FILENAME;
   18.77 +				}
   18.78 +				else if ( strcmp( argv[i], "-di" ) == 0 )
   18.79 +				{
   18.80 +					state = WAITING_FOR_DISC_INPUT_FILENAME;
   18.81 +				}
   18.82 +				else if ( strcmp( argv[i], "-boot" ) == 0 )
   18.83 +				{
   18.84 +					state = WAITING_FOR_BOOT_FILENAME;
   18.85 +				}
   18.86 +				else if ( strcmp( argv[i], "-v" ) == 0 )
   18.87 +				{
   18.88 +					GlobalData::Instance().SetVerbose( true );
   18.89 +				}
   18.90 +				else if ( strcmp( argv[i], "--help" ) == 0 )
   18.91 +				{
   18.92 +					cout << "beebasm " VERSION << endl << endl;
   18.93 +					cout << "Possible options:" << endl;
   18.94 +					cout << " -i <file>      Specify source filename" << endl;
   18.95 +					cout << " -di <file>     Specify a disc image file to be added to" << endl;
   18.96 +					cout << " -do <file>     Specify a disc image file to output" << endl;
   18.97 +					cout << " -boot <file>   Specify a filename to be run by !BOOT on a new disc image" << endl;
   18.98 +					cout << " -v             Verbose output" << endl;
   18.99 +					cout << " --help         See this help again" << endl;
  18.100 +				}
  18.101 +				else
  18.102 +				{
  18.103 +					cerr << "Bad parameter: " << argv[i] << endl;
  18.104 +					cerr << "Type beebasm --help for options" << endl;
  18.105 +					return EXIT_FAILURE;
  18.106 +				}
  18.107 +				break;
  18.108 +
  18.109 +
  18.110 +			case WAITING_FOR_INPUT_FILENAME:
  18.111 +
  18.112 +				pInputFile = argv[i];
  18.113 +				state = READY;
  18.114 +				break;
  18.115 +
  18.116 +
  18.117 +			case WAITING_FOR_DISC_OUTPUT_FILENAME:
  18.118 +
  18.119 +				pDiscOutputFile = argv[i];
  18.120 +				GlobalData::Instance().SetUseDiscImage( true );
  18.121 +				state = READY;
  18.122 +				break;
  18.123 +
  18.124 +
  18.125 +			case WAITING_FOR_DISC_INPUT_FILENAME:
  18.126 +
  18.127 +				pDiscInputFile = argv[i];
  18.128 +				state = READY;
  18.129 +				break;
  18.130 +
  18.131 +
  18.132 +			case WAITING_FOR_BOOT_FILENAME:
  18.133 +
  18.134 +				GlobalData::Instance().SetBootFile( argv[i] );
  18.135 +				state = READY;
  18.136 +				break;
  18.137 +		}
  18.138 +	}
  18.139 +
  18.140 +	if ( state != READY )
  18.141 +	{
  18.142 +		cerr << "Parameter error -" << endl;
  18.143 +		cerr << "Type beebasm -help for syntax" << endl;
  18.144 +		return EXIT_FAILURE;
  18.145 +	}
  18.146 +
  18.147 +	// Check parameters
  18.148 +
  18.149 +	if ( pInputFile == NULL )
  18.150 +	{
  18.151 +		cerr << "No source file" << endl;
  18.152 +		return EXIT_FAILURE;
  18.153 +	}
  18.154 +
  18.155 +	if ( pDiscInputFile != NULL && pDiscOutputFile == NULL ||
  18.156 +		 ( pDiscInputFile != NULL && pDiscOutputFile != NULL && strcmp( pDiscInputFile, pDiscOutputFile ) == 0 ) )
  18.157 +	{
  18.158 +		cerr << "If a disc image file is provided as input, a different filename must be provided as output" << endl;
  18.159 +		return EXIT_FAILURE;
  18.160 +	}
  18.161 +
  18.162 +
  18.163 +	// All good, start the assembling
  18.164 +
  18.165 +	int exitCode = EXIT_SUCCESS;
  18.166 +
  18.167 +	SymbolTable::Create();
  18.168 +	ObjectCode::Create();
  18.169 +
  18.170 +	time_t randomSeed = time( NULL );
  18.171 +
  18.172 +	DiscImage* pDiscIm = NULL;
  18.173 +
  18.174 +	try
  18.175 +	{
  18.176 +		if ( GlobalData::Instance().UsesDiscImage() )
  18.177 +		{
  18.178 +			pDiscIm = new DiscImage( pDiscOutputFile, pDiscInputFile );
  18.179 +			GlobalData::Instance().SetDiscImage( pDiscIm );
  18.180 +		}
  18.181 +
  18.182 +		for ( int pass = 0; pass < 2; pass++ )
  18.183 +		{
  18.184 +			GlobalData::Instance().SetPass( pass );
  18.185 +			ObjectCode::Instance().SetPC( 0 );
  18.186 +			ObjectCode::Instance().Clear( 0, 0x10000, false );
  18.187 +			GlobalData::Instance().ResetForId();
  18.188 +			srand( static_cast< unsigned int >( randomSeed ) );
  18.189 +			SourceFile input( pInputFile );
  18.190 +			input.Process();
  18.191 +		}
  18.192 +	}
  18.193 +	catch ( AsmException& e )
  18.194 +	{
  18.195 +		e.Print();
  18.196 +		exitCode = EXIT_FAILURE;
  18.197 +	}
  18.198 +
  18.199 +	delete pDiscIm;
  18.200 +
  18.201 +	ObjectCode::Destroy();
  18.202 +	SymbolTable::Destroy();
  18.203 +	GlobalData::Destroy();
  18.204 +
  18.205 +	return exitCode;
  18.206 +}
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/src/main.h	Sat May 01 19:35:42 2010 +0100
    19.3 @@ -0,0 +1,12 @@
    19.4 +/*************************************************************************************************/
    19.5 +/**
    19.6 +	main.h
    19.7 +*/
    19.8 +/*************************************************************************************************/
    19.9 +
   19.10 +#ifndef MAIN_H_
   19.11 +#define MAIN_H_
   19.12 +
   19.13 +
   19.14 +
   19.15 +#endif // MAIN_H_
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/src/objectcode.cpp	Sat May 01 19:35:42 2010 +0100
    20.3 @@ -0,0 +1,285 @@
    20.4 +/*************************************************************************************************/
    20.5 +/**
    20.6 +	objectcode.cpp
    20.7 +*/
    20.8 +/*************************************************************************************************/
    20.9 +
   20.10 +#include <cstring>
   20.11 +#include <iostream>
   20.12 +
   20.13 +#include "objectcode.h"
   20.14 +#include "symboltable.h"
   20.15 +#include "asmexception.h"
   20.16 +#include "globaldata.h"
   20.17 +
   20.18 +
   20.19 +ObjectCode* ObjectCode::m_gInstance = NULL;
   20.20 +
   20.21 +
   20.22 +using namespace std;
   20.23 +
   20.24 +
   20.25 +/*************************************************************************************************/
   20.26 +/**
   20.27 +	ObjectCode::Create()
   20.28 +
   20.29 +	Creates the ObjectCode singleton
   20.30 +*/
   20.31 +/*************************************************************************************************/
   20.32 +void ObjectCode::Create()
   20.33 +{
   20.34 +	assert( m_gInstance == NULL );
   20.35 +
   20.36 +	m_gInstance = new ObjectCode;
   20.37 +}
   20.38 +
   20.39 +
   20.40 +
   20.41 +/*************************************************************************************************/
   20.42 +/**
   20.43 +	ObjectCode::Destroy()
   20.44 +
   20.45 +	Destroys the ObjectCode singleton
   20.46 +*/
   20.47 +/*************************************************************************************************/
   20.48 +void ObjectCode::Destroy()
   20.49 +{
   20.50 +	assert( m_gInstance != NULL );
   20.51 +
   20.52 +	delete m_gInstance;
   20.53 +	m_gInstance = NULL;
   20.54 +}
   20.55 +
   20.56 +
   20.57 +
   20.58 +/*************************************************************************************************/
   20.59 +/**
   20.60 +	ObjectCode::ObjectCode()
   20.61 +
   20.62 +	ObjectCode constructor
   20.63 +*/
   20.64 +/*************************************************************************************************/
   20.65 +ObjectCode::ObjectCode()
   20.66 +	:	m_PC( 0 )
   20.67 +{
   20.68 +	memset( m_aMemory, 0, sizeof m_aMemory );
   20.69 +	memset( m_aFlags, 0, sizeof m_aFlags );
   20.70 +}
   20.71 +
   20.72 +
   20.73 +
   20.74 +/*************************************************************************************************/
   20.75 +/**
   20.76 +	ObjectCode::~ObjectCode()
   20.77 +
   20.78 +	ObjectCode destructor
   20.79 +*/
   20.80 +/*************************************************************************************************/
   20.81 +ObjectCode::~ObjectCode()
   20.82 +{
   20.83 +}
   20.84 +
   20.85 +
   20.86 +
   20.87 +/*************************************************************************************************/
   20.88 +/**
   20.89 +	ObjectCode::PutByte()
   20.90 +
   20.91 +	Puts one byte to memory image
   20.92 +*/
   20.93 +/*************************************************************************************************/
   20.94 +void ObjectCode::PutByte( unsigned int byte )
   20.95 +{
   20.96 +	if ( m_PC > 0xFFFF )
   20.97 +	{
   20.98 +		throw AsmException_AssembleError_OutOfMemory();
   20.99 +	}
  20.100 +
  20.101 +	assert( m_PC >= 0 && m_PC < 0x10000 );
  20.102 +	assert( byte < 0x100 );
  20.103 +
  20.104 +	if ( m_aFlags[ m_PC ] & GUARD )
  20.105 +	{
  20.106 +		throw AsmException_AssembleError_GuardHit();
  20.107 +	}
  20.108 +
  20.109 +	if ( m_aFlags[ m_PC ] & USED )
  20.110 +	{
  20.111 +		throw AsmException_AssembleError_Overlap();
  20.112 +	}
  20.113 +
  20.114 +	m_aFlags[ m_PC ] |= USED;
  20.115 +	m_aMemory[ m_PC++ ] = byte;
  20.116 +
  20.117 +	SymbolTable::Instance().ChangeSymbol( "P%", m_PC );
  20.118 +}
  20.119 +
  20.120 +
  20.121 +
  20.122 +/*************************************************************************************************/
  20.123 +/**
  20.124 +	ObjectCode::Assemble1()
  20.125 +
  20.126 +	Assembles one byte to memory image
  20.127 +*/
  20.128 +/*************************************************************************************************/
  20.129 +void ObjectCode::Assemble1( unsigned int opcode )
  20.130 +{
  20.131 +	if ( m_PC > 0xFFFF )
  20.132 +	{
  20.133 +		throw AsmException_AssembleError_OutOfMemory();
  20.134 +	}
  20.135 +
  20.136 +	assert( m_PC >= 0 && m_PC < 0x10000 );
  20.137 +	assert( opcode < 0x100 );
  20.138 +
  20.139 +	if ( GlobalData::Instance().IsSecondPass() &&
  20.140 +		 m_aMemory[ m_PC ] != opcode )
  20.141 +	{
  20.142 +		throw AsmException_AssembleError_InconsistentCode();
  20.143 +	}
  20.144 +
  20.145 +	if ( m_aFlags[ m_PC ] & GUARD )
  20.146 +	{
  20.147 +		throw AsmException_AssembleError_GuardHit();
  20.148 +	}
  20.149 +
  20.150 +	if ( m_aFlags[ m_PC ] & USED )
  20.151 +	{
  20.152 +		throw AsmException_AssembleError_Overlap();
  20.153 +	}
  20.154 +
  20.155 +	m_aFlags[ m_PC ] |= USED;
  20.156 +	m_aMemory[ m_PC++ ] = opcode;
  20.157 +
  20.158 +	SymbolTable::Instance().ChangeSymbol( "P%", m_PC );
  20.159 +}
  20.160 +
  20.161 +
  20.162 +
  20.163 +/*************************************************************************************************/
  20.164 +/**
  20.165 +	ObjectCode::Assemble2()
  20.166 +
  20.167 +	Assembles two bytes to memory image
  20.168 +*/
  20.169 +/*************************************************************************************************/
  20.170 +void ObjectCode::Assemble2( unsigned int opcode, unsigned int val )
  20.171 +{
  20.172 +	if ( m_PC > 0xFFFE )
  20.173 +	{
  20.174 +		throw AsmException_AssembleError_OutOfMemory();
  20.175 +	}
  20.176 +
  20.177 +	assert( m_PC >= 0 && m_PC < 0x10000 );
  20.178 +	assert( opcode < 0x100 );
  20.179 +	assert( val < 0x100 );
  20.180 +
  20.181 +	if ( GlobalData::Instance().IsSecondPass() &&
  20.182 +		 m_aMemory[ m_PC ] != opcode )
  20.183 +	{
  20.184 +		throw AsmException_AssembleError_InconsistentCode();
  20.185 +	}
  20.186 +
  20.187 +	if ( ( m_aFlags[ m_PC ] & GUARD ) ||
  20.188 +		 ( m_aFlags[ m_PC + 1 ] & GUARD ) )
  20.189 +	{
  20.190 +		throw AsmException_AssembleError_GuardHit();
  20.191 +	}
  20.192 +
  20.193 +	if ( ( m_aFlags[ m_PC ] & USED ) ||
  20.194 +		 ( m_aFlags[ m_PC + 1 ] & USED ) )
  20.195 +	{
  20.196 +		throw AsmException_AssembleError_Overlap();
  20.197 +	}
  20.198 +
  20.199 +	m_aFlags[ m_PC ] |= USED;
  20.200 +	m_aMemory[ m_PC++ ] = opcode;
  20.201 +	m_aFlags[ m_PC ] |= USED;
  20.202 +	m_aMemory[ m_PC++ ] = val;
  20.203 +
  20.204 +	SymbolTable::Instance().ChangeSymbol( "P%", m_PC );
  20.205 +}
  20.206 +
  20.207 +
  20.208 +
  20.209 +/*************************************************************************************************/
  20.210 +/**
  20.211 +	ObjectCode::Assemble3()
  20.212 +
  20.213 +	Assembles three bytes to memory image
  20.214 +*/
  20.215 +/*************************************************************************************************/
  20.216 +void ObjectCode::Assemble3( unsigned int opcode, unsigned int addr )
  20.217 +{
  20.218 +	if ( m_PC > 0xFFFD )
  20.219 +	{
  20.220 +		throw AsmException_AssembleError_OutOfMemory();
  20.221 +	}
  20.222 +
  20.223 +	assert( m_PC >= 0 && m_PC < 0x10000 );
  20.224 +	assert( opcode < 0x100 );
  20.225 +	assert( addr < 0x10000 );
  20.226 +
  20.227 +	if ( GlobalData::Instance().IsSecondPass() &&
  20.228 +		 m_aMemory[ m_PC ] != opcode )
  20.229 +	{
  20.230 +		throw AsmException_AssembleError_InconsistentCode();
  20.231 +	}
  20.232 +
  20.233 +	if ( ( m_aFlags[ m_PC ] & GUARD ) ||
  20.234 +		 ( m_aFlags[ m_PC + 1 ] & GUARD ) ||
  20.235 +		 ( m_aFlags[ m_PC + 2 ] & GUARD ) )
  20.236 +	{
  20.237 +		throw AsmException_AssembleError_GuardHit();
  20.238 +	}
  20.239 +
  20.240 +	if ( ( m_aFlags[ m_PC ] & USED ) ||
  20.241 +		 ( m_aFlags[ m_PC + 1 ] & USED ) ||
  20.242 +		 ( m_aFlags[ m_PC + 2 ] & USED ) )
  20.243 +	{
  20.244 +		throw AsmException_AssembleError_Overlap();
  20.245 +	}
  20.246 +
  20.247 +	m_aFlags[ m_PC ] |= USED;
  20.248 +	m_aMemory[ m_PC++ ] = opcode;
  20.249 +	m_aFlags[ m_PC ] |= USED;
  20.250 +	m_aMemory[ m_PC++ ] = addr & 0xFF;
  20.251 +	m_aFlags[ m_PC ] |= USED;
  20.252 +	m_aMemory[ m_PC++ ] = ( addr & 0xFF00 ) >> 8;
  20.253 +
  20.254 +	SymbolTable::Instance().ChangeSymbol( "P%", m_PC );
  20.255 +}
  20.256 +
  20.257 +
  20.258 +
  20.259 +/*************************************************************************************************/
  20.260 +/**
  20.261 +	ObjectCode::SetGuard()
  20.262 +*/
  20.263 +/*************************************************************************************************/
  20.264 +void ObjectCode::SetGuard( int addr )
  20.265 +{
  20.266 +	assert( addr >= 0 && addr < 0x10000 );
  20.267 +	m_aFlags[ addr ] |= GUARD;
  20.268 +}
  20.269 +
  20.270 +
  20.271 +
  20.272 +/*************************************************************************************************/
  20.273 +/**
  20.274 +	ObjectCode::Clear()
  20.275 +*/
  20.276 +/*************************************************************************************************/
  20.277 +void ObjectCode::Clear( int start, int end, bool bAll )
  20.278 +{
  20.279 +	assert( start < end );
  20.280 +	assert( start >= 0 && start < 0x10000 );
  20.281 +	assert( end > 0 && end <= 0x10000 );
  20.282 +
  20.283 +	if ( bAll )
  20.284 +	{
  20.285 +		memset( m_aMemory + start, 0, end - start );
  20.286 +	}
  20.287 +	memset( m_aFlags + start, 0, end - start );
  20.288 +}
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/src/objectcode.h	Sat May 01 19:35:42 2010 +0100
    21.3 @@ -0,0 +1,57 @@
    21.4 +/*************************************************************************************************/
    21.5 +/**
    21.6 +	objectcode.h
    21.7 +*/
    21.8 +/*************************************************************************************************/
    21.9 +
   21.10 +#ifndef OBJECTCODE_H_
   21.11 +#define OBJECTCODE_H_
   21.12 +
   21.13 +#include <cassert>
   21.14 +#include <cstdlib>
   21.15 +
   21.16 +
   21.17 +class ObjectCode
   21.18 +{
   21.19 +public:
   21.20 +
   21.21 +	static void Create();
   21.22 +	static void Destroy();
   21.23 +	static inline ObjectCode& Instance() { assert( m_gInstance != NULL ); return *m_gInstance; }
   21.24 +
   21.25 +	inline void SetPC( int i )		{ m_PC = i; }
   21.26 +	inline int GetPC() const		{ return m_PC; }
   21.27 +
   21.28 +	inline const unsigned char* GetAddr( int i ) const { return m_aMemory + i; }
   21.29 +
   21.30 +	void PutByte( unsigned int byte );
   21.31 +	void Assemble1( unsigned int opcode );
   21.32 +	void Assemble2( unsigned int opcode, unsigned int val );
   21.33 +	void Assemble3( unsigned int opcode, unsigned int addr );
   21.34 +
   21.35 +	void SetGuard( int i );
   21.36 +	void Clear( int start, int end, bool bAll = true );
   21.37 +
   21.38 +
   21.39 +private:
   21.40 +
   21.41 +	enum FLAGS
   21.42 +	{
   21.43 +		USED  = (1 << 0),
   21.44 +		GUARD = (1 << 1)
   21.45 +	};
   21.46 +
   21.47 +
   21.48 +	ObjectCode();
   21.49 +	~ObjectCode();
   21.50 +
   21.51 +	unsigned char				m_aMemory[ 0x10000 ];
   21.52 +	unsigned char				m_aFlags[ 0x10000 ];
   21.53 +	int							m_PC;
   21.54 +
   21.55 +	static ObjectCode*			m_gInstance;
   21.56 +};
   21.57 +
   21.58 +
   21.59 +
   21.60 +#endif // OBJECTCODE_H_
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/src/sourcefile.cpp	Sat May 01 19:35:42 2010 +0100
    22.3 @@ -0,0 +1,348 @@
    22.4 +/*************************************************************************************************/
    22.5 +/**
    22.6 +	sourcefile.cpp
    22.7 +
    22.8 +	Assembles a file
    22.9 +*/
   22.10 +/*************************************************************************************************/
   22.11 +
   22.12 +#include <iostream>
   22.13 +#include <iomanip>
   22.14 +#include <sstream>
   22.15 +
   22.16 +#include "sourcefile.h"
   22.17 +#include "asmexception.h"
   22.18 +#include "stringutils.h"
   22.19 +#include "globaldata.h"
   22.20 +#include "lineparser.h"
   22.21 +#include "symboltable.h"
   22.22 +
   22.23 +
   22.24 +using namespace std;
   22.25 +
   22.26 +
   22.27 +
   22.28 +/*************************************************************************************************/
   22.29 +/**
   22.30 +	SourceFile::SourceFile()
   22.31 +
   22.32 +	Constructor for SourceFile
   22.33 +
   22.34 +	@param		pFilename		Filename of source file to open
   22.35 +
   22.36 +	The supplied file will be opened.  If there is a problem, an AsmException will be thrown.
   22.37 +*/
   22.38 +/*************************************************************************************************/
   22.39 +SourceFile::SourceFile( const char* pFilename )
   22.40 +	:	m_pFilename( pFilename ),
   22.41 +		m_lineNumber( 1 ),
   22.42 +		m_filePointer( 0 )
   22.43 +{
   22.44 +	// we have to open in binary, due to a bug in MinGW which means that calling
   22.45 +	// tellg() on a text-mode file ruins the file pointer!
   22.46 +	// http://www.mingw.org/MinGWiki/index.php/Known%20Problems
   22.47 +	m_file.open( pFilename, ios_base::binary );
   22.48 +
   22.49 +	if ( !m_file )
   22.50 +	{
   22.51 +		throw AsmException_FileError_OpenSourceFile( pFilename );
   22.52 +	}
   22.53 +}
   22.54 +
   22.55 +
   22.56 +
   22.57 +/*************************************************************************************************/
   22.58 +/**
   22.59 +	SourceFile::~SourceFile()
   22.60 +
   22.61 +	Destructor for SourceFile
   22.62 +
   22.63 +	The associated source file will be closed.
   22.64 +*/
   22.65 +/*************************************************************************************************/
   22.66 +SourceFile::~SourceFile()
   22.67 +{
   22.68 +	m_file.close();
   22.69 +}
   22.70 +
   22.71 +
   22.72 +
   22.73 +/*************************************************************************************************/
   22.74 +/**
   22.75 +	SourceFile::Process()
   22.76 +
   22.77 +	Process the associated source file
   22.78 +*/
   22.79 +/*************************************************************************************************/
   22.80 +void SourceFile::Process()
   22.81 +{
   22.82 +	// Initialise for stack
   22.83 +
   22.84 +	m_forStackPtr = 0;
   22.85 +
   22.86 +	// Initialise if
   22.87 +
   22.88 +	m_ifStackPtr = 0;
   22.89 +
   22.90 +	// Iterate through the file line-by-line
   22.91 +
   22.92 +	string lineFromFile;
   22.93 +
   22.94 +	while ( getline( m_file, lineFromFile ) )
   22.95 +	{
   22.96 +		// Convert tabs to spaces
   22.97 +
   22.98 +		StringUtils::ExpandTabsToSpaces( lineFromFile, 8 );
   22.99 +
  22.100 +//		// Display and process
  22.101 +//
  22.102 +//		if ( GlobalData::Instance().IsFirstPass() )
  22.103 +//		{
  22.104 +//			cout << setw( 5 ) << m_lineNumber << ": " << lineFromFile << endl;
  22.105 +//		}
  22.106 +
  22.107 +		try
  22.108 +		{
  22.109 +			LineParser thisLine( this, lineFromFile );
  22.110 +			thisLine.Process();
  22.111 +		}
  22.112 +		catch ( AsmException_SyntaxError& e )
  22.113 +		{
  22.114 +			// Augment exception with more details
  22.115 +			e.SetFilename( m_pFilename );
  22.116 +			e.SetLineNumber( m_lineNumber );
  22.117 +			throw;
  22.118 +		}
  22.119 +
  22.120 +		m_lineNumber++;
  22.121 +		m_filePointer = m_file.tellg();
  22.122 +	}
  22.123 +
  22.124 +	// Check whether we aborted prematurely
  22.125 +
  22.126 +	if ( !m_file.eof() )
  22.127 +	{
  22.128 +		throw AsmException_FileError_ReadSourceFile( m_pFilename );
  22.129 +	}
  22.130 +
  22.131 +	// Check that we have no FOR mismatch
  22.132 +
  22.133 +	if ( m_forStackPtr > 0 )
  22.134 +	{
  22.135 +		For& mismatchedFor = m_forStack[ m_forStackPtr - 1 ];
  22.136 +
  22.137 +		AsmException_SyntaxError_ForWithoutNext e( mismatchedFor.m_line, mismatchedFor.m_column );
  22.138 +		e.SetFilename( m_pFilename );
  22.139 +		e.SetLineNumber( mismatchedFor.m_lineNumber );
  22.140 +		throw e;
  22.141 +	}
  22.142 +
  22.143 +	// Check that we have no IF mismatch
  22.144 +
  22.145 +	if ( m_ifStackPtr > 0 )
  22.146 +	{
  22.147 +		If& mismatchedIf = m_ifStack[ m_ifStackPtr - 1 ];
  22.148 +
  22.149 +		AsmException_SyntaxError_IfWithoutEndif e( mismatchedIf.m_line, mismatchedIf.m_column );
  22.150 +		e.SetFilename( m_pFilename );
  22.151 +		e.SetLineNumber( mismatchedIf.m_lineNumber );
  22.152 +		throw e;
  22.153 +	}
  22.154 +
  22.155 +	// Display ok message
  22.156 +
  22.157 +	if ( GlobalData::Instance().IsFirstPass() )
  22.158 +	{
  22.159 +		cout << "Processed file '" << m_pFilename << "' ok" << endl << endl;
  22.160 +	}
  22.161 +}
  22.162 +
  22.163 +
  22.164 +
  22.165 +/*************************************************************************************************/
  22.166 +/**
  22.167 +	SourceFile::AddFor()
  22.168 +*/
  22.169 +/*************************************************************************************************/
  22.170 +void SourceFile::AddFor( string varName,
  22.171 +						 double start,
  22.172 +						 double end,
  22.173 +						 double step,
  22.174 +						 int filePtr,
  22.175 +						 string line,
  22.176 +						 int column )
  22.177 +{
  22.178 +	if ( m_forStackPtr == MAX_FOR_LEVELS )
  22.179 +	{
  22.180 +		throw AsmException_SyntaxError_TooManyFORs( line, column );
  22.181 +	}
  22.182 +
  22.183 +	// Add symbol to table
  22.184 +
  22.185 +	SymbolTable::Instance().AddSymbol( varName, start );
  22.186 +
  22.187 +	// Fill in FOR block
  22.188 +
  22.189 +	m_forStack[ m_forStackPtr ].m_varName		= varName;
  22.190 +	m_forStack[ m_forStackPtr ].m_current		= start;
  22.191 +	m_forStack[ m_forStackPtr ].m_end			= end;
  22.192 +	m_forStack[ m_forStackPtr ].m_step			= step;
  22.193 +	m_forStack[ m_forStackPtr ].m_filePtr		= filePtr;
  22.194 +	m_forStack[ m_forStackPtr ].m_id			= GlobalData::Instance().GetNextForId();
  22.195 +	m_forStack[ m_forStackPtr ].m_count			= 0;
  22.196 +	m_forStack[ m_forStackPtr ].m_line			= line;
  22.197 +	m_forStack[ m_forStackPtr ].m_column		= column;
  22.198 +	m_forStack[ m_forStackPtr ].m_lineNumber	= m_lineNumber;
  22.199 +
  22.200 +	m_forStackPtr++;
  22.201 +}
  22.202 +
  22.203 +
  22.204 +
  22.205 +/*************************************************************************************************/
  22.206 +/**
  22.207 +	SourceFile::UpdateFor()
  22.208 +*/
  22.209 +/*************************************************************************************************/
  22.210 +void SourceFile::UpdateFor( string line, int column )
  22.211 +{
  22.212 +	if ( m_forStackPtr == 0 )
  22.213 +	{
  22.214 +		throw AsmException_SyntaxError_NextWithoutFor( line, column );
  22.215 +	}
  22.216 +
  22.217 +	For& thisFor = m_forStack[ m_forStackPtr - 1 ];
  22.218 +
  22.219 +	thisFor.m_current += thisFor.m_step;
  22.220 +
  22.221 +	if ( ( thisFor.m_step > 0.0 && thisFor.m_current > thisFor.m_end ) ||
  22.222 +		 ( thisFor.m_step < 0.0 && thisFor.m_current < thisFor.m_end ) )
  22.223 +	{
  22.224 +		// we have reached the end of the FOR
  22.225 +		SymbolTable::Instance().RemoveSymbol( thisFor.m_varName );
  22.226 +		m_forStackPtr--;
  22.227 +	}
  22.228 +	else
  22.229 +	{
  22.230 +		// reloop
  22.231 +		SymbolTable::Instance().ChangeSymbol( thisFor.m_varName, thisFor.m_current );
  22.232 +		SetFilePointer( thisFor.m_filePtr );
  22.233 +		thisFor.m_count++;
  22.234 +		m_lineNumber = thisFor.m_lineNumber - 1;
  22.235 +	}
  22.236 +}
  22.237 +
  22.238 +
  22.239 +
  22.240 +/*************************************************************************************************/
  22.241 +/**
  22.242 +	SourceFile::GetSymbolNameSuffix()
  22.243 +*/
  22.244 +/*************************************************************************************************/
  22.245 +string SourceFile::GetSymbolNameSuffix( int level ) const
  22.246 +{
  22.247 +	if ( level == -1 )
  22.248 +	{
  22.249 +		level = m_forStackPtr;
  22.250 +	}
  22.251 +
  22.252 +	ostringstream suffix;
  22.253 +
  22.254 +	for ( int i = 0; i < level; i++ )
  22.255 +	{
  22.256 +		suffix << "@";
  22.257 +		suffix << m_forStack[ i ].m_id;
  22.258 +		suffix << "_";
  22.259 +		suffix << m_forStack[ i ].m_count;
  22.260 +	}
  22.261 +
  22.262 +	return suffix.str();
  22.263 +}
  22.264 +
  22.265 +
  22.266 +
  22.267 +/*************************************************************************************************/
  22.268 +/**
  22.269 +	SourceFile::IsIfConditionTrue()
  22.270 +*/
  22.271 +/*************************************************************************************************/
  22.272 +bool SourceFile::IsIfConditionTrue() const
  22.273 +{
  22.274 +	for ( int i = 0; i < m_ifStackPtr; i++ )
  22.275 +	{
  22.276 +		if ( !m_ifStack[ i ].m_condition )
  22.277 +		{
  22.278 +			return false;
  22.279 +		}
  22.280 +	}
  22.281 +
  22.282 +	return true;
  22.283 +}
  22.284 +
  22.285 +
  22.286 +
  22.287 +/*************************************************************************************************/
  22.288 +/**
  22.289 +	SourceFile::AddIfLevel()
  22.290 +*/
  22.291 +/*************************************************************************************************/
  22.292 +void SourceFile::AddIfLevel( string line, int column )
  22.293 +{
  22.294 +	if ( m_ifStackPtr == MAX_IF_LEVELS )
  22.295 +	{
  22.296 +		throw AsmException_SyntaxError_TooManyIFs( line, column );
  22.297 +	}
  22.298 +
  22.299 +	m_ifStack[ m_ifStackPtr ].m_condition	= true;
  22.300 +	m_ifStack[ m_ifStackPtr ].m_line		= line;
  22.301 +	m_ifStack[ m_ifStackPtr ].m_column		= column;
  22.302 +	m_ifStack[ m_ifStackPtr ].m_lineNumber	= m_lineNumber;
  22.303 +	m_ifStackPtr++;
  22.304 +}
  22.305 +
  22.306 +
  22.307 +
  22.308 +/*************************************************************************************************/
  22.309 +/**
  22.310 +	SourceFile::SetCurrentIfCondition()
  22.311 +*/
  22.312 +/*************************************************************************************************/
  22.313 +void SourceFile::SetCurrentIfCondition( bool b )
  22.314 +{
  22.315 +	assert( m_ifStackPtr > 0 );
  22.316 +	m_ifStack[ m_ifStackPtr - 1 ].m_condition = b;
  22.317 +}
  22.318 +
  22.319 +
  22.320 +
  22.321 +/*************************************************************************************************/
  22.322 +/**
  22.323 +	SourceFile::ToggleCurrentIfCondition()
  22.324 +*/
  22.325 +/*************************************************************************************************/
  22.326 +void SourceFile::ToggleCurrentIfCondition( string line, int column )
  22.327 +{
  22.328 +	if ( m_ifStackPtr == 0 )
  22.329 +	{
  22.330 +		throw AsmException_SyntaxError_ElseWithoutIf( line, column );
  22.331 +	}
  22.332 +
  22.333 +	m_ifStack[ m_ifStackPtr - 1 ].m_condition = !m_ifStack[ m_ifStackPtr - 1 ].m_condition;
  22.334 +}
  22.335 +
  22.336 +
  22.337 +
  22.338 +/*************************************************************************************************/
  22.339 +/**
  22.340 +	SourceFile::RemoveIfLevel()
  22.341 +*/
  22.342 +/*************************************************************************************************/
  22.343 +void SourceFile::RemoveIfLevel( string line, int column )
  22.344 +{
  22.345 +	if ( m_ifStackPtr == 0 )
  22.346 +	{
  22.347 +		throw AsmException_SyntaxError_EndifWithoutIf( line, column );
  22.348 +	}
  22.349 +
  22.350 +	m_ifStackPtr--;
  22.351 +}
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/src/sourcefile.h	Sat May 01 19:35:42 2010 +0100
    23.3 @@ -0,0 +1,102 @@
    23.4 +/*************************************************************************************************/
    23.5 +/**
    23.6 +	sourcefile.h
    23.7 +*/
    23.8 +/*************************************************************************************************/
    23.9 +
   23.10 +#ifndef SOURCEFILE_H_
   23.11 +#define SOURCEFILE_H_
   23.12 +
   23.13 +#include <fstream>
   23.14 +#include <string>
   23.15 +#include <vector>
   23.16 +
   23.17 +
   23.18 +class SourceFile
   23.19 +{
   23.20 +public:
   23.21 +
   23.22 +	// Constructor/destructor (RAII class)
   23.23 +
   23.24 +	explicit SourceFile( const char* pFilename );
   23.25 +	~SourceFile();
   23.26 +
   23.27 +	// Process the file
   23.28 +
   23.29 +	void Process();
   23.30 +
   23.31 +	// Accessors
   23.32 +
   23.33 +	inline const char*		GetFilename() const				{ return m_pFilename; }
   23.34 +	inline int				GetLineNumber() const			{ return m_lineNumber; }
   23.35 +	inline int				GetFilePointer() const			{ return m_filePointer; }
   23.36 +	inline void				SetFilePointer( int i )			{ m_filePointer = i; m_file.seekg( i ); }
   23.37 +
   23.38 +	// For loop / if related stuff
   23.39 +
   23.40 +	#define MAX_FOR_LEVELS	16
   23.41 +	#define MAX_IF_LEVELS	16
   23.42 +
   23.43 +private:
   23.44 +
   23.45 +	struct For
   23.46 +	{
   23.47 +		std::string			m_varName;
   23.48 +		double				m_current;
   23.49 +		double				m_end;
   23.50 +		double				m_step;
   23.51 +		int					m_filePtr;
   23.52 +		int					m_id;
   23.53 +		int					m_count;
   23.54 +		std::string			m_line;
   23.55 +		int					m_column;
   23.56 +		int					m_lineNumber;
   23.57 +	};
   23.58 +
   23.59 +	For						m_forStack[ MAX_FOR_LEVELS ];
   23.60 +	int						m_forStackPtr;
   23.61 +
   23.62 +	struct If
   23.63 +	{
   23.64 +		bool				m_condition;
   23.65 +		std::string			m_line;
   23.66 +		int					m_column;
   23.67 +		int					m_lineNumber;
   23.68 +	};
   23.69 +
   23.70 +	int						m_ifStackPtr;
   23.71 +	If						m_ifStack[ MAX_IF_LEVELS ];
   23.72 +
   23.73 +public:
   23.74 +
   23.75 +	void					AddFor( std::string varName,
   23.76 +									double start,
   23.77 +									double end,
   23.78 +									double step,
   23.79 +									int filePtr,
   23.80 +									std::string line,
   23.81 +									int column );
   23.82 +
   23.83 +	void					UpdateFor( std::string line, int column );
   23.84 +
   23.85 +	inline int 				GetForLevel() const { return m_forStackPtr; }
   23.86 +
   23.87 +	std::string				GetSymbolNameSuffix( int level = -1 ) const;
   23.88 +
   23.89 +	bool					IsIfConditionTrue() const;
   23.90 +	void					AddIfLevel( std::string line, int column );
   23.91 +	void					SetCurrentIfCondition( bool b );
   23.92 +	void					ToggleCurrentIfCondition( std::string line, int column );
   23.93 +	void					RemoveIfLevel( std::string line, int column );
   23.94 +
   23.95 +
   23.96 +private:
   23.97 +
   23.98 +	std::ifstream			m_file;
   23.99 +	const char*				m_pFilename;
  23.100 +	int						m_lineNumber;
  23.101 +	int						m_filePointer;
  23.102 +};
  23.103 +
  23.104 +
  23.105 +#endif // SOURCEFILE_H_
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/src/stringutils.cpp	Sat May 01 19:35:42 2010 +0100
    24.3 @@ -0,0 +1,78 @@
    24.4 +/*************************************************************************************************/
    24.5 +/**
    24.6 +	stringutils.cpp
    24.7 +*/
    24.8 +/*************************************************************************************************/
    24.9 +
   24.10 +#include <iostream>
   24.11 +#include "stringutils.h"
   24.12 +
   24.13 +using namespace std;
   24.14 +
   24.15 +
   24.16 +namespace StringUtils
   24.17 +{
   24.18 +
   24.19 +
   24.20 +/*************************************************************************************************/
   24.21 +/**
   24.22 +	ExpandTabsToSpaces()
   24.23 +
   24.24 +	Globally replaces all tab characters in the string with spaces
   24.25 +*/
   24.26 +/*************************************************************************************************/
   24.27 +void ExpandTabsToSpaces( string& line, size_t tabWidth )
   24.28 +{
   24.29 +	(void)tabWidth;
   24.30 +	size_t index;
   24.31 +
   24.32 +	while ( ( index = line.find( '\t' ) ) != string::npos )
   24.33 +	{
   24.34 +		// use the below if you want to align to tab stops
   24.35 +		// line.replace( index, 1, string( tabWidth - index % tabWidth, ' ' ) );
   24.36 +
   24.37 +		line.replace( index, 1, " " );
   24.38 +	}
   24.39 +
   24.40 +	// This method is now misnamed as I now also process \r\n to become just \n.
   24.41 +	// This means it might not work on every platform, but I had to do this because of a
   24.42 +	// bug in MinGW regarding handling of files opened in 'text' mode.
   24.43 +	while ( ( index = line.find( '\r' ) ) != string::npos )
   24.44 +	{
   24.45 +		line.replace( index, 1, "" );
   24.46 +	}
   24.47 +}
   24.48 +
   24.49 +
   24.50 +
   24.51 +/*************************************************************************************************/
   24.52 +/**
   24.53 +	EatWhitespace()
   24.54 +
   24.55 +	Moves to the first non-whitespace character
   24.56 +
   24.57 +	@param		line			String to process
   24.58 +	@param		column			Character within the string to start from
   24.59 +
   24.60 +	@return		bool			Whether there were more non-whitespace characters found
   24.61 +				column is modified to the next non-whitespace character, or the end of the string
   24.62 +*/
   24.63 +/*************************************************************************************************/
   24.64 +bool EatWhitespace( const string& line, size_t& column )
   24.65 +{
   24.66 +	size_t newColumn = line.find_first_not_of( " \t\r\n", column );
   24.67 +	if ( newColumn == string::npos )
   24.68 +	{
   24.69 +		column = line.length();
   24.70 +		return false;
   24.71 +	}
   24.72 +	else
   24.73 +	{
   24.74 +		column = newColumn;
   24.75 +		return true;
   24.76 +	}
   24.77 +}
   24.78 +
   24.79 +
   24.80 +
   24.81 +} // namespace StringUtils
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/src/stringutils.h	Sat May 01 19:35:42 2010 +0100
    25.3 @@ -0,0 +1,20 @@
    25.4 +/*************************************************************************************************/
    25.5 +/**
    25.6 +	stringutils.h
    25.7 +*/
    25.8 +/*************************************************************************************************/
    25.9 +
   25.10 +#ifndef STRINGUTILS_H_
   25.11 +#define STRINGUTILS_H_
   25.12 +
   25.13 +#include <string>
   25.14 +
   25.15 +
   25.16 +namespace StringUtils
   25.17 +{
   25.18 +	void ExpandTabsToSpaces( std::string& line, size_t tabWidth );
   25.19 +	bool EatWhitespace( const std::string& line, size_t& column );
   25.20 +}
   25.21 +
   25.22 +
   25.23 +#endif // STRINGUTILS_H_
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/src/symboltable.cpp	Sat May 01 19:35:42 2010 +0100
    26.3 @@ -0,0 +1,162 @@
    26.4 +/*************************************************************************************************/
    26.5 +/**
    26.6 +	symboltable.cpp
    26.7 +*/
    26.8 +/*************************************************************************************************/
    26.9 +
   26.10 +#include <cmath>
   26.11 +#include "symboltable.h"
   26.12 +
   26.13 +SymbolTable* SymbolTable::m_gInstance = NULL;
   26.14 +
   26.15 +
   26.16 +
   26.17 +/*************************************************************************************************/
   26.18 +/**
   26.19 +	SymbolTable::Create()
   26.20 +
   26.21 +	Creates the SymbolTable singleton
   26.22 +*/
   26.23 +/*************************************************************************************************/
   26.24 +void SymbolTable::Create()
   26.25 +{
   26.26 +	assert( m_gInstance == NULL );
   26.27 +
   26.28 +	m_gInstance = new SymbolTable;
   26.29 +}
   26.30 +
   26.31 +
   26.32 +
   26.33 +/*************************************************************************************************/
   26.34 +/**
   26.35 +	SymbolTable::Destroy()
   26.36 +
   26.37 +	Destroys the SymbolTable singleton
   26.38 +*/
   26.39 +/*************************************************************************************************/
   26.40 +void SymbolTable::Destroy()
   26.41 +{
   26.42 +	assert( m_gInstance != NULL );
   26.43 +
   26.44 +	delete m_gInstance;
   26.45 +	m_gInstance = NULL;
   26.46 +}
   26.47 +
   26.48 +
   26.49 +
   26.50 +/*************************************************************************************************/
   26.51 +/**
   26.52 +	SymbolTable::SymbolTable()
   26.53 +
   26.54 +	SymbolTable constructor
   26.55 +*/
   26.56 +/*************************************************************************************************/
   26.57 +SymbolTable::SymbolTable()
   26.58 +{
   26.59 +	// Add any constant symbols here
   26.60 +
   26.61 +	AddSymbol( "PI", M_PI );
   26.62 +	AddSymbol( "P%", 0 );
   26.63 +	AddSymbol( "TRUE", -1 );
   26.64 +	AddSymbol( "FALSE", 0 );
   26.65 +}
   26.66 +
   26.67 +
   26.68 +
   26.69 +/*************************************************************************************************/
   26.70 +/**
   26.71 +	SymbolTable::~SymbolTable()
   26.72 +
   26.73 +	SymbolTable destructor
   26.74 +*/
   26.75 +/*************************************************************************************************/
   26.76 +SymbolTable::~SymbolTable()
   26.77 +{
   26.78 +}
   26.79 +
   26.80 +
   26.81 +
   26.82 +/*************************************************************************************************/
   26.83 +/**
   26.84 +	SymbolTable::IsSymbolDefined()
   26.85 +
   26.86 +	Returns whether or not the supplied symbol exists in the symbol table
   26.87 +
   26.88 +	@param		symbol			The symbol to search for
   26.89 +	@returns	bool
   26.90 +*/
   26.91 +/*************************************************************************************************/
   26.92 +bool SymbolTable::IsSymbolDefined( const std::string& symbol ) const
   26.93 +{
   26.94 +	return ( m_map.count( symbol ) == 1 );
   26.95 +}
   26.96 +
   26.97 +
   26.98 +
   26.99 +/*************************************************************************************************/
  26.100 +/**
  26.101 +	SymbolTable::AddSymbol()
  26.102 +
  26.103 +	Adds a symbol to the symbol table with the supplied value
  26.104 +
  26.105 +	@param		symbol			The symbol to add
  26.106 +	@param		int				Its value
  26.107 +*/
  26.108 +/*************************************************************************************************/
  26.109 +void SymbolTable::AddSymbol( const std::string& symbol, double value )
  26.110 +{
  26.111 +	assert( !IsSymbolDefined( symbol ) );
  26.112 +	m_map.insert( make_pair( symbol, value ) );
  26.113 +}
  26.114 +
  26.115 +
  26.116 +
  26.117 +/*************************************************************************************************/
  26.118 +/**
  26.119 +	SymbolTable::GetSymbol()
  26.120 +
  26.121 +	Gets the value of a symbol which already exists in the symbol table
  26.122 +
  26.123 +	@param		symbol			The name of the symbol to look for
  26.124 +*/
  26.125 +/*************************************************************************************************/
  26.126 +double SymbolTable::GetSymbol( const std::string& symbol ) const
  26.127 +{
  26.128 +	assert( IsSymbolDefined( symbol ) );
  26.129 +	return m_map.find( symbol )->second;
  26.130 +}
  26.131 +
  26.132 +
  26.133 +
  26.134 +/*************************************************************************************************/
  26.135 +/**
  26.136 +	SymbolTable::ChangeSymbol()
  26.137 +
  26.138 +	Changes the value of a symbol which already exists in the symbol table
  26.139 +
  26.140 +	@param		symbol			The name of the symbol to look for
  26.141 +	@param		value			Its new value
  26.142 +*/
  26.143 +/*************************************************************************************************/
  26.144 +void SymbolTable::ChangeSymbol( const std::string& symbol, double value )
  26.145 +{
  26.146 +	assert( IsSymbolDefined( symbol ) );
  26.147 +	m_map.find( symbol )->second = value;
  26.148 +}
  26.149 +
  26.150 +
  26.151 +
  26.152 +/*************************************************************************************************/
  26.153 +/**
  26.154 +	SymbolTable::RemoveSymbol()
  26.155 +
  26.156 +	Removes the named symbol
  26.157 +
  26.158 +	@param		symbol			The name of the symbol to look for
  26.159 +*/
  26.160 +/*************************************************************************************************/
  26.161 +void SymbolTable::RemoveSymbol( const std::string& symbol )
  26.162 +{
  26.163 +	assert( IsSymbolDefined( symbol ) );
  26.164 +	m_map.erase( symbol );
  26.165 +}
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/src/symboltable.h	Sat May 01 19:35:42 2010 +0100
    27.3 @@ -0,0 +1,43 @@
    27.4 +/*************************************************************************************************/
    27.5 +/**
    27.6 +	symboltable.h
    27.7 +*/
    27.8 +/*************************************************************************************************/
    27.9 +
   27.10 +#ifndef SYMBOLTABLE_H_
   27.11 +#define SYMBOLTABLE_H_
   27.12 +
   27.13 +#include <cassert>
   27.14 +#include <cstdlib>
   27.15 +#include <map>
   27.16 +#include <string>
   27.17 +
   27.18 +
   27.19 +class SymbolTable
   27.20 +{
   27.21 +public:
   27.22 +
   27.23 +	static void Create();
   27.24 +	static void Destroy();
   27.25 +	static inline SymbolTable& Instance() { assert( m_gInstance != NULL ); return *m_gInstance; }
   27.26 +
   27.27 +	void AddSymbol( const std::string& symbol, double value );
   27.28 +	void ChangeSymbol( const std::string& symbol, double value );
   27.29 +	double GetSymbol( const std::string& symbol ) const;
   27.30 +	bool IsSymbolDefined( const std::string& symbol ) const;
   27.31 +	void RemoveSymbol( const std::string& symbol );
   27.32 +
   27.33 +
   27.34 +private:
   27.35 +
   27.36 +	SymbolTable();
   27.37 +	~SymbolTable();
   27.38 +
   27.39 +	std::map<std::string, double>	m_map;
   27.40 +
   27.41 +	static SymbolTable*				m_gInstance;
   27.42 +};
   27.43 +
   27.44 +
   27.45 +
   27.46 +#endif // SYMBOLTABLE_H_
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/src/tokens.h	Sat May 01 19:35:42 2010 +0100
    28.3 @@ -0,0 +1,36 @@
    28.4 +/*************************************************************************************************/
    28.5 +/**
    28.6 +	tokens.h
    28.7 +
    28.8 +	All the data used by the assembler
    28.9 +*/
   28.10 +/*************************************************************************************************/
   28.11 +
   28.12 +// Token table
   28.13 +
   28.14 +LineParser::Token	LineParser::m_gaTokenTable[] =
   28.15 +{
   28.16 +	{ ".",			&LineParser::HandleDefineLabel },
   28.17 +	{ "\\",			&LineParser::HandleDefineComment },
   28.18 +	{ ";",			&LineParser::HandleDefineComment },
   28.19 +	{ ":",			&LineParser::HandleStatementSeparator },
   28.20 +	{ "PRINT",		&LineParser::HandlePrint },
   28.21 +	{ "ORG",		&LineParser::HandleOrg },
   28.22 +	{ "INCLUDE",	&LineParser::HandleInclude },
   28.23 +	{ "EQUB",		&LineParser::HandleEqub },
   28.24 +	{ "EQUS",		&LineParser::HandleEqub },
   28.25 +	{ "EQUW",		&LineParser::HandleEquw },
   28.26 +	{ "SAVE",		&LineParser::HandleSave },
   28.27 +	{ "FOR",		&LineParser::HandleFor },
   28.28 +	{ "NEXT",		&LineParser::HandleNext },
   28.29 +	{ "IF",			&LineParser::HandleIf },
   28.30 +	{ "ELSE",		&LineParser::HandleElse },
   28.31 +	{ "ENDIF",		&LineParser::HandleEndif },
   28.32 +	{ "ALIGN",		&LineParser::HandleAlign },
   28.33 +	{ "SKIP",		&LineParser::HandleSkip }
   28.34 +};
   28.35 +
   28.36 +
   28.37 +
   28.38 +
   28.39 +