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 +
