MaxCoderz

for your 1 bit pleasure!

All times are UTC




Post new topic Reply to topic  [ 68 posts ]  Go to page Previous  1, 2, 3, 4, 5  Next
Author Message
 Post subject:
PostPosted: Tue 02 Oct, 2007 1:02 pm 
Offline
Maxcoderz Staff
User avatar

Joined: Thu 16 Dec, 2004 10:06 pm
Posts: 3064
Location: Croydon, England
I've been comparing binaries output by old Brass and this new assembler (pixelmad.z80, eliza.z80, CoBB's pinball.asm, kv's slip.z80, Joe P's asteroid.z80), and finally(!) the two are matching (the usual errors of reading ld de,(xyz)+1 as ld de,(*) and so on seem to have been fixed).

There's a large amount of error trapping to add (for example, bcall(xyz) where bcall hasn't been defined creates a new label, bcall(xyz), rather than raising an error), more testing and the addition of the many missing features (.defcont, .deflong, .var, structs, reusable labels, ...) that I haven't got around to yet.

I hope to get a demo out soon for testing :D


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed 03 Oct, 2007 10:12 am 
Offline
Maxcoderz Staff
User avatar

Joined: Thu 16 Dec, 2004 10:06 pm
Posts: 3064
Location: Croydon, England
Various parser updates and fixes have been implemented (including reintroduced support for the ternary conditional operator ?: ).

Slightly strangely, ?: has very low operator precedence. This means that in the following expression:

Code:
x = 0
y = true() ? ++x : --x


y is 0, not 1. The reason for this is that as ?: has low precedence, it gets evaluated after both ++x and --x.

To further confuse issues, before adding ternary operator support to the parser I implemented an if() function, like this:

Code:
x = 0
y = if(true(), ++x, --x)


This was inspired by VB's IIf() function. However, as this function can pick and choose which expressions to evaluate, y becomes 1. This is backwards to convention where the C-style ?: operator is lazy (only executing the successful side) and the BASIC-style if() isn't, executing both sides first.

Multi-line statements are the next area of contention. Currently a statement is terminated with a newline or a \ character. However, in some special cases, this termination is disabled - for example, by the .define directive. Another directive that does this is the .enum directive, which results in syntax like this:

Code:
.enum Days
   Sunday,
   Monday,
   Tuesday,
   Wednesday,
   Thursday,
   Friday,
   Saturday
\

/*
This creates the following labels:
Days.Sunday   = 0
Days.Monday   = 1
Days.Tuesday  = 2
...
Days.Saturday = 6
*/

.enum Numbers
   Eleven = 11,
   Twelve,
   Thirteen,
   Twenty = 20,
   Vingt = 20,
   Zwanzig = 20,
   TwentyOne,
   Four = 4,
   Five
\

.echoln Numbers.Eleven    ; 11
.echoln Numbers.Twelve    ; 12
.echoln Numbers.Thirteen  ; 13
.echoln Numbers.Twenty    ; 20
.echoln Numbers.Vingt     ; 20
.echoln Numbers.Zwanzig   ; 20
.echoln Numbers.TwentyOne ; 21
.echoln Numbers.Four      ; 4
.echoln Numbers.Five      ; 5


I think that using the \ termination character is rather neat. Others may disagree, so I'd like to hear your ideas. :)

In a similar vein, I've added support for runtime-aliased plugins. This can be used by a user-defined function plugin, so the following is now possible:

Code:
; A recursive function that calculates n!
.function factorial(n)
   if(n <= 0, 1, n * factorial(n - 1))
\

; 1.5511210043331E+25
.echoln factorial(25)


Finally, for silliness, I've added a new plugin collection that handles images:

Code:
; Open the image:
img = imgopen("delete.png")

; Loop over each pixel in the image:
.for y = 0, y < imgheight(img), ++y
   .for x = 0, x < imgwidth(img), ++x
   
      ; Grab the luminosity of each pixel to two bits:
      l = imggetpixel(img, x, y, 'l2')
      
      ; Convert to an 'ASCII-art' brightness:
      c = choose(l + 1, ' ', '.', '+', '#')
      .echochar c, c
      
   .loop
   .echoln
.loop

/*
          ....++++....
        ++++########++..
      ++######++++++##++..
    ++++##++++++++++++##++..
  ..++##++++++++++++++++##..
  ..##++++++++++++++++++++++..
  ++##++++############++++++..
  ++##++++############++++++..
  ..++++++++++++++++++++++++..
  ....##++++++++++++++++++..
    ..++++++++++++++++++++..
      ..++++++++++++++++..
        ....++++++++....
            ........
*/


"l2" in imggetpixel is the pixel format you want - for example, "argb" or "b2g2r2" (if no width is specified, 8 bits is assumed).

It might look useless, but it at least gives me some decent parser testing material. :)


Last edited by benryves on Wed 03 Oct, 2007 11:55 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed 03 Oct, 2007 11:20 am 
Offline
Calc King
User avatar

Joined: Sun 23 Jan, 2005 12:37 am
Posts: 1727
Location: Netherlands
Dude, seriously :) What's next? A can opener? :)

I think the backslash is a bit confusing, being the Unix minded guy that I am, as it usually represents that the line continues beyond the \n, not that it ends...

You'd expect:
Code:
.define bcall(xyz) \
      rst 28h \
      .dw xyz


not
Code:
.define bcall(xyz)
      rst 28h
      .dw xyz
\

_________________
http://clap.timendus.com/ - The Calculator Link Alternative Protocol
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed 03 Oct, 2007 11:41 am 
Offline
Maxcoderz Staff
User avatar

Joined: Thu 16 Dec, 2004 10:06 pm
Posts: 3064
Location: Croydon, England
The parser sees both \ and the carriage return as statement terminators; it needs to see \ as a statement terminator (rather than line continuation) for TASM's sake (hence the bcall macro expanding to "rst 28h \ .dw label").

Requiring an explicit end-of-statement character (like C's ';') isn't going to work (would break compatibility with all other source files, assembly is line based). We rather need to keep \ as a terminator, but one could introduce a line continuation character like BASIC's _:

Code:
.define bcall(xyz) _
      rst 28h _
      .dw xyz


Then the enum would have to look like:

Code:
.enum Days
   Sunday, _
   Monday,  _
   Tuesday, _
   Wednesday, _
   Thursday, _
   Friday, _
   Saturday


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed 03 Oct, 2007 12:35 pm 
Offline
Calc King

Joined: Sat 05 Aug, 2006 7:22 am
Posts: 1513
Or you could use a completely different character as 'closing char', } ] | > or something, or..
.endenum
.enddefine
but that's old-style..


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed 03 Oct, 2007 1:03 pm 
Offline
Maxcoderz Staff
User avatar

Joined: Thu 16 Dec, 2004 10:06 pm
Posts: 3064
Location: Croydon, England
Yes, I was originally going to use .end*, but that requires more stuff hacked into the parser to catch that sort if thing.

It's appealing in the sense that other directives, such as the repetition ones (.for/.loop/.while or .if) require a terminating directive (.loop or .endif).

The choices are there, this is why I'm asking you lot what you think I should go for :D


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed 03 Oct, 2007 5:21 pm 
Offline
Extreme Poster
User avatar

Joined: Thu 17 May, 2007 4:49 pm
Posts: 395
Location: $4080
how about:
Code:
.enum days
   Monday, Tuesday, Wednesday,    ; Though comments should be allowed here
   Thursday, Friday,
   Saturday, Sunday
; Done because there is no ","

basically if a "," is appended then there is a next statement (eventually on the next line)
Nice and clean ^^

This can be generalised:
Code:
.db 0,0,0,0,
0,0,0

This would then be valid, or (if you don't want this) you could give these kind of directives a flag:
true=allows statements to continue on the next line
false=the opposite of true

And all TASM source files will compile properly under the new Brass



Though this approach does not work with .define :(
and I don't see a way (other than \ and .defcont) to handle this
.function shouldn't be a problem for backward compatibility (because it doesn't exists in TASM :P)
Code:
.function test (par1, par2) {/*code goes here*/ xor a\ ld b, a\ ld c, a
   ld h, par1
   ld l, par2
; Note that I have no idea how the function system works
; thus the last 2 lines can be completely illegal :P
}


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed 03 Oct, 2007 5:36 pm 
Offline
Maxcoderz Staff
User avatar

Joined: Thu 16 Dec, 2004 10:06 pm
Posts: 3064
Location: Croydon, England
I do rather like that idea (if last non-whitespace/non-comment token is a comma = ignore newlines).

Functions currently only allow mathematical expressions (so not even directives work in them) which needs to be fixed anyway; I'd rather use a .function/.endfunction pair and let the user put anything they like inside them. I'll need to add a public method to the compiler that will let a plugin author "inject" some code.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed 03 Oct, 2007 7:35 pm 
Offline
Calc King

Joined: Sat 05 Aug, 2006 7:22 am
Posts: 1513
Good idea! it looks really natural so that is good


I'll remember this forever :)
Quote:
false=the opposite of true


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed 03 Oct, 2007 9:55 pm 
Offline
Extreme Poster
User avatar

Joined: Thu 17 May, 2007 4:49 pm
Posts: 395
Location: $4080
King Harold wrote:
I'll remember this forever
Dries wrote:
false=the opposite of true
XD that is one to remember, the most hilarious things happen when you least expect it :mrgreen:

One little thing though:
Do you have to start the enumeration on the next line you write .enum? maybe you can have one big list and take the first statement as the name. This allows more flexibility:
Code:
.enum name,
 one, two, three,
 test1, test2, test3

Code:
.enum name, one, two, three


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu 04 Oct, 2007 9:23 am 
Offline
Maxcoderz Staff
User avatar

Joined: Thu 16 Dec, 2004 10:06 pm
Posts: 3064
Location: Croydon, England
Code:
.enum name item1, item2, item3

...is also valid. The first item is the name, it's just the rest of the line that needs to be comma-delimited.

I implemented your comma trick and it works very well, so thanks for the idea. :)

Functions now work "properly" (and in about a third of the lines of the original function implementation!) The compiler pulls in source code, tokenises and caches it (after matching assembly source code and directives) in a big list. You can recall the current statement and tell the compiler to jump to a particular statement (by index), which is how the looping directives work.

The function plugin, then, simply has to remember the current position +1 (entry point), switch off the compiler (which means that nothing is executed until a matching directive is hit, in this case .endfunction), remember the current position -1 (exit point). When the function is invoked it just asks "recompile statements between entry point and exit point". :)

A few sample snippets:

Code:
/* Output the eight bits of value as 1s or 0s */
.function echobinary(value)
   .for bit is 7 to 0
      .if value & 1 << bit
         .echo 1
      .else
         .echo 0
      .endif
   .loop
.endfunction

/* Output the eight bits of value as 1s or 0s with a % prefix */
.function echobinarybyte(value)
   .echo '%' \ echobinary(value)
.endfunction

/* Output the sixteen bits of value as 1s or 0s with a % prefix */
.function echobinaryword(value)
   .echo '%'
   echobinary(value >> 8)
   echobinary(value)
.endfunction

/* Output the four bits of value as a hex digit */
.function echohexnybble(value)
   .echochar choose(1 + (value & %1111),
      '0', '1', '2', '3', '4', '5', '6', '7',
      '8', '9', 'A', 'B', 'C', 'D', 'E', 'F')
.endfunction

/* Output the eight bits of value as two hex digits */
.function echohex(value)
   echohexnybble(value >> 4)
   echohexnybble(value)
.endfunction

/* Output the eight bits of value as two hex digits */
.function echohexbyte(value)
   .echo '$' \ echohex(value)
.endfunction

/* Output the eight bits of value as two hex digits */
.function echohexword(value)
   .echo '$'
   echohex(value >> 8)
   echohex(value)
.endfunction

echobinaryword(1234) ; Outputs %0000010011010010
.echoln

echohexword(%1011111011101111) ; Outputs $BEEF
.echoln


Code:
/* Enumeration for different calculator models */
#enum Model
   TI8X, ; TI-83 Plus
   TI83  ; TI-83

/* Set to TI8X or TI83 */
Model = Model.TI83

/* Use bcall() to invoke ROM calls */
#function bcall(label)
   .if Model == Model.TI8X
      rst 28h
      .dw label
   .else
      call label
   .endif
#endfunction


Code:
#function f(n)
   .if n == 0
      f = 1
   .else
      f = n * f(n - 1)
   .endif
#endfunction

.echoln f(30) ; Outputs 2.65252859812191E+32.


Code:
.function distance(x,y)
   distance = sqrt(x * x + y * y)
.endfunction

.echoln distance(3, 4) ; Outputs 5.


When called, the arguments are evaluated then passed (as local labels in a new, temporary module) into the function. This has some disadvantages; such as passing in a label that may or may not be declared (for example):

Code:
.function lda(value)
    .if defined(value) && value == 0
        xor a
    .else
        ld a,value
    .endif
.endfunction

lda(fowardreference) ; Error

forwardreference = 100


The easiest way to implement this would be to use constraints on function declarations:

Code:
.function lda(value) where defined(value) && value ==0
        xor a
.endfunction

.function lda(value)
    ld a,value
.endfunction


Where you have multiple declarations for functions you'd pick the most specific one that matches. Another possibility would be to use macro substitution with arguments rather than evaluate them:

Code:
.function lda(macro value)
        ; ...
.endfunction


The macro idea has the added feature that you can use it to pass-by-reference and also pass string literals and suchlike. Both have their advantages, so I might go for both, but - as always - I'd like to know your opinions.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu 04 Oct, 2007 5:23 pm 
Offline
Extreme Poster
User avatar

Joined: Thu 17 May, 2007 4:49 pm
Posts: 395
Location: $4080
benryves wrote:
I implemented your comma trick and it works very well, so thanks for the idea. :)
No problem at all :D


benryves wrote:
The function plugin, then, simply has to remember the current position +1 (entry point), switch off the compiler (which means that nothing is executed until a matching directive is hit, in this case .endfunction), remember the current position -1 (exit point). When the function is invoked it just asks "recompile statements between entry point and exit point".
I got nothing to add :P


benryves wrote:
Code:
/* Output the eight bits of value as 1s or 0s */
.function echobinary(value)
   .for bit is 7 to 0
      .if value & 1 << bit
         .echo 1
      .else
         .echo 0
      .endif
   .loop
.endfunction
as long as in ".for bit is 7 to 0" (there's no need to be able to modify 7 in the loop) 0 can be modified in the loop itself, like:
Code:
value=5
.for par is 0 to value
  .db value
  value=value-1
.loop
This should output:
Code:
.db 5,4,3,2 ;I suppose it terminates when par>value (and not >=)



Ah, you can still choose between "." and "#" for directive prefixes


Some notes:
why do you use textual delimiters instead of commas? (no idea if that sentence makes sense ^^)
this is feels better imo:
Code:
;(1)
.for bit=7, bit<=0, bit=bit-1
.loop

;(2)
.for bit,7,0
.loop
the only problem with (1) is that some mastermind may write a condition that is never reached :mrgreen:, though I still prefer (2) over the textual delimiters and (1) over (2)


benryves wrote:
When called, the arguments are evaluated then passed (as local labels in a new, temporary module) into the function.
...
...
...
Both have their advantages, so I might go for both, but - as always - I'd like to know your opinions.

I don't understand this part...
parameters of a function shouldn't be labels (as labels can only store numbers), rather some textual representations of some content. though how will you make the difference between labels and parameters...
I'm confused about it...

Anyway I am glad I can help you make Brass even better (and it's looking so good already!!!) :D


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu 04 Oct, 2007 5:33 pm 
Offline
Maxcoderz Staff
User avatar

Joined: Thu 16 Dec, 2004 10:06 pm
Posts: 3064
Location: Croydon, England
Two different for loops are supplied:
Code:
; "C-style"
.for <initialisation>, <condition>, <increment>
.loop

; "BASIC-style"
.for <label> is <start> to <end> [step <increment>]
.loop

The use of commas vs text is just to differentate between the two more easily.

Quote:
...shouldn't be labels (as labels can only store numbers), rather some textual representations of some content. though how will you make the difference between labels and parameters...
This is why I suggested the use of a "macro" argument, so:

Code:
.function repeatstring(macro x, repeat)
    .for i=0, i < repeat, ++i
        .db x
    .loop
.endfunction

repeatstring("Hello", 3) ; Outputs "HelloHelloHello"


"x" is not evaluated and gets macro-replaced into the ".db" statement, but "repeat" gets evaluated as a number.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu 04 Oct, 2007 7:06 pm 
Offline
Extreme Poster
User avatar

Joined: Thu 17 May, 2007 4:49 pm
Posts: 395
Location: $4080
Just PERFECT! :D

benryves wrote:
"x" is not evaluated and gets macro-replaced into the ".db" statement, but "repeat" gets evaluated as a number.

yes you will need to support them both:
you can just find/replace macro arguments, but you can't do that with the numbers because they can be changed during the function (macro arguments cannot)

Ok that isn't very good English... :P
All I want to say is find/replace macro arguments and always re-evaluate labels

Which is just as you said :P


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri 05 Oct, 2007 7:18 am 
Offline
Calc King

Joined: Sat 05 Aug, 2006 7:22 am
Posts: 1513
What would happen if you tried to name something "macro"?


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 68 posts ]  Go to page Previous  1, 2, 3, 4, 5  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB ® Forum Software © phpBB Group | DVGFX2 by: Matt