lazymake/lazy65 - a ca65 pre-parser

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

Post Reply
User avatar
miau
Posts: 188
Joined: Mon Nov 06, 2006 9:34 am
Location: Potsdam, Germany
Contact:

lazymake/lazy65 - a ca65 pre-parser

Post by miau »

Hey folks,

I got fed up with having to write header files and ca65's limitations when working with scopes so I created this little tool.
This is what it allows you to do:

File: Module.z

Code: Select all

.segment "CODE"
func1:

.proc func2
	var1: .reszp 1
.endproc

.macro someMacro arg1, arg2
.endmacro
File: main.z

Code: Select all

.use Module

main:
	jsr Module.func1
	
	lda #0
	sta Module.func2.var
	jsr Module.func2
	
	Module.someMacro 1, 2

Code: Select all

> lazy65 Module
> lazy65 main
This will generate ca65-compatible header and source files that you can integrate into your build process. However, a generic build script (lazymake) is also included which can take care of everything for you.
Python 2 is required.

==============
DOWNLOAD
lazy65 V0.1.4 (current) (May 13, 2015)
lazy65 V0.1.3 (May 18, 2014)
lazy65 V0.1.2 (May 11, 2014)
lazy65 V0.1.1 (May 3, 2014)
lazy65 V0.1.0
==============

Planned features
  • - python macros (.pymacro)
  • - automatic generation of linker config files for common mappers
  • - maybe a couple of extra commands that make life easier
The tool is still in a somewhat early stage and currently identifies and replaces symbols in a rather lazy way which may result in cryptic error messages, I'm hoping to fix that in a later version. If you decide to give it a try, please let me know if you encounter any problems. There may be unresolved bugs with certain ca65 commands (.struct?) that need fixing.
Last edited by miau on Thu May 21, 2015 9:26 am, edited 10 times in total.
User avatar
Movax12
Posts: 541
Joined: Sun Jan 02, 2011 11:50 am

Re: lazy65 - a ca65 pre-parser

Post by Movax12 »

I did a kind of hacky thing with macros to scope macros that are a part of a header interface:
viewtopic.php?p=112437#p112437

Not sure if I will keep it, but the idea isn't too messy and it does work, with the only downside being you can't access a variable constant, as in:
myscope::foo .set 1
Since it will be interpreted as a macro call. Also, if there is an error in a macro call you'll get a couple of extra error messages as the errors trace through the macro calls. (You may need higher verbosity setting to see this.)
User avatar
thefox
Posts: 3134
Joined: Mon Jan 03, 2005 10:36 am
Location: 🇫🇮
Contact:

Re: lazy65 - a ca65 pre-parser

Post by thefox »

Seems cool.

I don't know if I'm in the minority here, but when I installed Python on Windows, it didn't by default associate .py files to run with Python. So just typing "lazymake.py" doesn't work here (I have .py associated with a text editor).

One way to fix that could be to provide lazy65.cmd and lazymake.cmd (for Windows) and lazy65 and lazymake shell scripts (for *nix) in the base directory. Then a simple "lazy65" or "lazymake" could be used to invoke the scripts.

lazy65.cmd and lazymake.cmd could look like this:

Code: Select all

@echo off
python %~dpn0.py %*
Not sure what the *nix counterparts would be. Also need to change LAZY65 in lazymake.py from lazy65.py to lazy65. I think I may have missed some other place where it tries to run lazy65.py, because when I run lazymake, lazy65.py opens in my text editor. :)

Aaaand, not sure if I just messed something up with my changes, but when I run lazymake, it occasionally picks a different compilation order and fails to compile the "basic" example.

Here's a run that failed (didn't compile Graphics before main):

Code: Select all

C:\Users\f\Downloads\lazy65-0.1.0\examples\basic>lazymake
lazy65 -s "src" -o "obj" Global
lazy65 -s "src" -o "obj" Module
lazy65 -s "src" -o "obj" Graphics.Sprite
lazy65 -s "src" -o "obj" Graphics.Tile
lazy65 -s "src" -o "obj" main
Traceback (most recent call last):
  File "C:\Users\f\Downloads\lazy65-0.1.0\lazy65.py", line 92, in <module>
    main()
  File "C:\Users\f\Downloads\lazy65-0.1.0\lazy65.py", line 80, in main
    lines = parser.parse() #2nd pass
  File "C:\Users\f\Downloads\lazy65-0.1.0\src\tempy.py", line 46, in parse
    self.lineCallback()
  File "C:\Users\f\Downloads\lazy65-0.1.0\lazy65.py", line 20, in lineCallback
    asm.parse()
  File "C:\Users\f\Downloads\lazy65-0.1.0\src\Assembler.py", line 185, in parse
    self.command(tok.text)
  File "C:\Users\f\Downloads\lazy65-0.1.0\src\Assembler.py", line 385, in command
    self.importModule(moduleName, scopeName, True, True)
  File "C:\Users\f\Downloads\lazy65-0.1.0\src\Assembler.py", line 115, in importModule
    self.importSingleModule(moduleName, scopeName, generateIncludes)
  File "C:\Users\f\Downloads\lazy65-0.1.0\src\Assembler.py", line 85, in importS
ingleModule
    with open(symfile,'rb') as f:
IOError: [Errno 2] No such file or directory: 'obj/Graphics.sym'
lazymake.py: Error 1
And here's a one that succeeded (I did lazymake clean inbetween):

Code: Select all

C:\Users\f\Downloads\lazy65-0.1.0\examples\basic>lazymake
lazy65 -s "src" -o "obj" Global
lazy65 -s "src" -o "obj" Module
lazy65 -s "src" -o "obj" Graphics.Sprite
lazy65 -s "src" -o "obj" Graphics.Tile
lazy65 -s "src" -o "obj" Graphics
lazy65 -s "src" -o "obj" main
ca65 "obj/Global.s" -o "obj/Global.o"
ca65 "obj/main.s" -o "obj/main.o"
ca65 "obj/Module.s" -o "obj/Module.o"
ca65 "obj/Graphics/Sprite.s" -o "obj/Graphics/Sprite.o"
ca65 "obj/Graphics/Tile.s" -o "obj/Graphics/Tile.o"
ca65 "obj/Graphics.s" -o "obj/Graphics.o"
ld65 -o "basic.nes" -C linker.cfg "obj/Global.o" "obj/main.o" "obj/Module.o" "ob
j/Graphics/Sprite.o" "obj/Graphics/Tile.o" "obj/Graphics.o"
basic.nes: Build complete
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
User avatar
miau
Posts: 188
Joined: Mon Nov 06, 2006 9:34 am
Location: Potsdam, Germany
Contact:

Re: lazy65 - a ca65 pre-parser

Post by miau »

Movax12 wrote:I did a kind of hacky thing with macros to scope macros that are a part of a header interface:
viewtopic.php?p=112437#p112437
Oh, I never checked that topic again. Interesting. A bit of nasty boilerplate code, but still, it goes to show how powerful ca65 really is.
thefox wrote:lazy65.cmd and lazymake.cmd could look like this...
Thanks, added them!
thefox wrote:Aaaand, not sure if I just messed something up with my changes, but when I run lazymake, it occasionally picks a different compilation order and fails to compile the "basic" example.
It was most likely a race condition with the multi-threaded compilation going on. Anyway, thanks for your feedback, I added dependency file generation and based the build system around it which will hopefully eliminate these errors.

Updated download link in first post.
User avatar
thefox
Posts: 3134
Joined: Mon Jan 03, 2005 10:36 am
Location: 🇫🇮
Contact:

Re: lazy65 - a ca65 pre-parser

Post by thefox »

Trivial error on line 85 in Assembler.py:

Code: Select all

C:\Users\f\Downloads\lazy65-011\examples\basic>lazymake
lazy65 --sym-only -s "src" -o "obj" Module
Traceback (most recent call last):
  File "C:\Users\f\Downloads\lazy65-011\lazy65.py", line 8, in <module>
    from src.Assembler import Assembler
  File "C:\Users\f\Downloads\lazy65-011\src\Assembler.py", line 85
    raise tempy.Error('Could not create symbol file for module '+moduleName+')
                                                                             ^
SyntaxError: EOL while scanning string literal
lazymake.py: Error 1
And if you want to add *nix support, this "npm" shell script from node.js may be a good template to base "lazy65" and "lazymake" on:

Code: Select all

#!/bin/sh

basedir=`dirname "$0"`

case `uname` in
    *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac

if [ -x "$basedir/node.exe" ]; then
  "$basedir/node.exe" "$basedir/node_modules/npm/bin/npm-cli.js" "$@"
else
  node "$basedir/node_modules/npm/bin/npm-cli.js" "$@"
fi
EDIT: In hindsight, I'm not sure if this script is the same one that ships with the *nix installations of node.js.
Last edited by thefox on Mon May 05, 2014 2:29 am, edited 1 time in total.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
User avatar
miau
Posts: 188
Joined: Mon Nov 06, 2006 9:34 am
Location: Potsdam, Germany
Contact:

Re: lazy65 - a ca65 pre-parser

Post by miau »

Woops, fixed.
Cool. I am going to look into that.
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: lazy65 - a ca65 pre-parser

Post by lidnariq »

*nix support should just involve having the right #! line in the original python script... and preferably not having ".py" in the command name, which is probably best solved with symlinks.
User avatar
thefox
Posts: 3134
Joined: Mon Jan 03, 2005 10:36 am
Location: 🇫🇮
Contact:

Re: lazy65 - a ca65 pre-parser

Post by thefox »

lidnariq wrote:*nix support should just involve having the right #! line in the original python script... and preferably not having ".py" in the command name, which is probably best solved with symlinks.
How do you plan to put a symlink in a zip file?
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: lazy65 - a ca65 pre-parser

Post by lidnariq »

Zip doesn't preserve the executable bit either, so it already requires finessing: zip is poorly suited to unixy things. The options are "accept having .py at your command line", "use a different compressor" (tgz, 7z, rar), or "rename the files to not end with .py"
User avatar
thefox
Posts: 3134
Joined: Mon Jan 03, 2005 10:36 am
Location: 🇫🇮
Contact:

Re: lazy65 - a ca65 pre-parser

Post by thefox »

lidnariq wrote:Zip doesn't preserve the executable bit either
True.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
User avatar
miau
Posts: 188
Joined: Mon Nov 06, 2006 9:34 am
Location: Potsdam, Germany
Contact:

Re: lazy65 - a ca65 pre-parser

Post by miau »

Updated. Fixed a couple of bugs and added the custom commands .reszp and .resbss.

This:

Code: Select all

.proc func
    .segment "ZEROPAGE"
        localvar: .res 1
    .segment "CODE"
    rts
.endproc
can now be written like this:

Code: Select all

.proc func
    localvar: .reszp 1
    rts
.endproc
.reszp and .resbss use the ca65 commands .pushseg and .popseg when translated so the segment you are in will be automatically restored.

I also got rid of the .py extensions so now the tools can be called the same way in both Windows and Linux (by just typing "lazy65" or "lazymake").
User avatar
Movax12
Posts: 541
Joined: Sun Jan 02, 2011 11:50 am

Re: lazy65 - a ca65 pre-parser

Post by Movax12 »

I like the res command. I did that too (macros):

Code: Select all

 ; Example of declaring variables using .struct syntax.
        resZP { \
                foo     .byte ,     \
                bar     .word ,     \
                test    .addr 6     \
        }
 
        resBSS { myVar  .byte, yourVar  .addr 4 }
        resBSS  baz     .byte
Post Reply