Giter Club home page Giter Club logo

bass's Introduction

Addicted to programming since 1985

http://minnberg.se/page/resume/

Claim to fame (software actually used by peole)

  • Chipmachine -- Demoscene/retro music player with global incremental search

  • DroidSound -- First real mod/sid player for Android devices

  • PogoShell -- Popular graphical shell for the Gameboy Advance

  • Tiger -- the first emulator for the 68000 based TI-92 calculator

Videos by me

C++ and the 6502

C++ and the 6502

R-Toy Presentation

R-Toy presentation

Tricks, Tips, and a couple of war stories

Tricks & Tips

C++ Mobile development

Tricks & Tips

bass's People

Contributors

antis81 avatar sasq64 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

bass's Issues

parsing loop in PASS 1

Had the assembler (version: 0a9f7fd -> "dev") running into a parsing loop (100% cpu - waited >15s). Couldn't reproduce this for a test yet…

(clearing basscache had no effect)

compiling on OpenBSD

  1. The small operator function _N needs to be renamed, something is already defined to that name:

[ 66%] Building CXX object CMakeFiles/badlib.dir/src/assembler.cpp.o
/root/src/bass/src/assembler.cpp:189:19: error: expected identifier
Number operator"" _N(unsigned long long a)
^
/usr/include/ctype.h:47:12: note: expanded from macro '_N' #define _N 0x04 ^ /root/src/bass/src/assembler.cpp:198:20: error: no matching literal operator for
call to 'operator""_N' with argument of type 'unsigned long long' or
'const char *', and no matching literal operator template
{"A", 0_N}, {"X", 0_N}, {"Y", 0_N}, {"SR", 0_N},

Just renaming it to _NumOp and replacing the 7 occurrences on the lines following made it work.

  1. va_list from external/coreutils/.../log.h is named __va_list on OpenBSD, either detect the OS and change it, or include stdarg.h to define va_list.

Diff for both attached, seems to pass "make test" on both MacOS and OpenBSD, but markup seem to mangle it,
the patch is also available from c64/bass.patch

`diff --git a/external/coreutils/src/coreutils/log.h b/external/coreutils/src/coreutils/log.h
index 43a08e4..c5ef1b0 100644
--- a/external/coreutils/src/coreutils/log.h
+++ b/external/coreutils/src/coreutils/log.h
@@ -3,6 +3,7 @@
#include "format.h"
#include
#include
+#include <stdarg.h>

namespace logging {

diff --git a/src/assembler.cpp b/src/assembler.cpp
index 0e8767c..0365882 100644
--- a/src/assembler.cpp
+++ b/src/assembler.cpp
@@ -186,7 +186,7 @@ int Assembler::checkUndefined()
return PASS;
}

-Number operator"" _N(unsigned long long a)
+Number operator"" _NumOp(unsigned long long a)
{
return static_cast(a);
}
@@ -195,8 +195,8 @@ AnyMap Assembler::runTest(std::string_view name, std::string_view contents)
{
if (!finalPass) {
return {

  •        {"A", 0_N},  {"X", 0_N},  {"Y", 0_N},      {"SR", 0_N},
    
  •        {"SP", 0_N}, {"PC", 0_N}, {"cycles", 0_N}, {"ram", mach->getRam()}};
    
  •        {"A", 0_NumOp},  {"X", 0_NumOp},  {"Y", 0_NumOp},      {"SR", 0_NumOp},
    
  •        {"SP", 0_NumOp}, {"PC", 0_NumOp}, {"cycles", 0_NumOp}, {"ram", mach->getRam()}};
    

    }

    auto saved = save();
    `

"!include" vs "!import" vs "include guards"

The !include meta command does what the name states - so far so good. However it does not check if a file has been included already and multiple !include statements for the same file lead to actual code copies and followup errors in turn.

  • May this actually be useful for some case?
    • What about an additional !import then?
  • Do we need include guards? (kick has #importonce, C++ has #pragma once, etc.)

Personally I prefer !import, but maybe you have something different in mind…

Sub label scopes

Macros and rept statements introduce a temporary lastLabel and then restores the previous one.
This allows for local labels within those scopes only.

But it fails if you try to nest macros/repts.

We should use a stack of labels instead of the single lastLabel, and search up the stack
so we can support this.

!macro hey(a) {
   .x = a + 1
   .y = a + 2
   !rept 4 {
      .x = .y * 2 ; Should find above .y (a + 2)
      !rept 4 {
          .z = .x + .y ; Should find .x in parent rept scope and .y in top macro scope.
      }
   }
}

prevent symbol overriding by another type

After the merge of #18 I noticed that doesn't handle a (rather important) corner case…

The following test shows this is not handled by the parser yet:

symbol_0  ; label
;!error <TBD>
symbol_0  = "overrides symbol_0 (changing type from label to var)"

On the other hand re-assigning a var is fine:

symbol_1 = 1233
symbol_1 = symbol_1 + 1  ; re-assigning is good :)

This can be handled with the "final" flag and basically relies on the "const" definition of a label type.

Note this only applies to assignment types as other symbols (macro, enum, section, … ) are named "anonymously" - thus clearly distinguish from each other.

[request] support for fixed length arrays

Defining static arrays is an issue using the !rept. meta when the array label is local. Example:

a_scope:  <-- Trying to define local "a_scope.arr[idx]" labels (actually this is a "__macro_<id>" label in my case)
  .arr:  ; <-- should have indexed .arr[<i>] labels
  !rept 5 { 
    ; note: scope is now "__rept_<id>"
    .arr[i]: !byte 0  ; results in "__rept_<id>.my_arr[<i>]" label -> practically invisible
  }

A solution to this could be a new !array meta command:

a_scope:
  !array .arr, 5  ; defines "a_scope.arr"
  {
    .arr[i]: !byte 0  ; defines "a_scope.arr[<i>]
  }

… or (probably better) we could allow explicit definition of sub labels:

a_scope:
  !rept 5 {
    a_scope.arr[i]: !byte 0  ; currently a syntax error
  }

[request] treat macro parameters as local symbol references

(Referring to current "dev" branch here.)
Should macro parameters (assignments in braces) in bass be treated just like macro-local references?

ACME example (suitable as a test):

!macro inc_store ~.var, ~.call {  ;no braces in ACME
   .var = .var+1  ;var_1 = 43
   jsr .call
}


;zeropage
!section "zp", start=0x0
*=0x2
stored_result: !byte 0

!section "calls", start=0x1234
var_1 = 42
call:
  .store:
     lda #var_1
     sta stored_result
     rts

; start of program
!section "code", start=*
inc_store(var_1, call.store) ;-> stored_result = 43
; do something with stored_result
inc_store(var_1, call.store) ;-> stored_result = 44
; do more with stored_result

Can't we treat all macro parameters by reference and as well imply those are macro-local?

Macro in bass according to the above example:

!macro inc_store(var, call) {
  ; defines:
  ;   __macro_0.var = ~var_1  ; reference to global label
  ;   __macro_0.call = ~call.store
   
  .var = .var+1  ;var_1 = var_1+1 -> breaks the "__macro_0" scope)
  jsr .call
}

💡 This can solve/replace the "shadowed symbol" list (solve it for good!?).
💡 The main issue is with global labels inside macros producing unwanted side effects (e.g. overwrite the __macro_<ID> label).

Comment lines without newline before EOT can result in "syntax error"

Usually an EOL (newline) is optional at the end of each text file.

In my project however I am using quite some (lua & asm) includes.
Having one of them ending with a comment line without newline before end-of-file produces a "syntax error" at exactly that line:

; included.asm

!macro inc_macro(value) {
    ; macro code
}

; comment without newline  <- "sporadic" syntax error
; main.asm

!include "included.asm"
!include "another_include.asm"
!script "script_include.lua"

; more code…

It may be important to the issue that the file is included. This is reproducible with my project - unfortunately not with any test-code I tried (even the above example should be parsed fine).

💡 Workaround: Add a newline at the end of each file.

Section relocation

Locating a section based on a label (example in section_move test) creates quite complex dependency issues when defined after being accessed (-> below a section).

Here is a simplified version of the test visualizing the problem:

!section "circular", circular_label
    
   ; meanwhile some code lines later… :)

circular_label:

    ; whoops…

To support this the ownership of a label (symbol actually) has to be defined. The above situation creates a circular dependency. Currently bass is unable to detect such programming error (that's basically what it is… 🙂).

bug: macro tries to redefine local label

Having the following situation:

!macro some_macro(v0) { 
.macro_label:
  ; some content 
  rts
}

It seems to work fine when the macro is instantiated within the same label context (same pass?):

label_0:
  some_macro(1)
  some_macro(2)

Fails when the macro is instantiated in different label contexts:

label_0: some_macro(1)
label_1: some_macro(2)  ;<--- fails with "already defined label __macro_<id>.macro_label"

Macro ID's should always be "unique" right?

And yes, I am totally aware that implementation of the "final" flag on symbols is incomplete. 😇

[bug] endless loop

ℹ️ Reason was an undefined symbol somewhere completely else in code than initially thought -> Not reproducible.

Without further debugging yet…
The following construct leads to an endless loop:

!section "arr", start=$9000, size=arr.Size, NoStore=true
arr:
  .Width = 64          ; width & height a 2D array (64x64 -> 4KiB)
  .Size = pow(.Width,2)
  !fill .Size, 0
  .end = *-1

In short: The code above works!

macro sections

While assembling with the current "dev" version I stumbled upon the following warning:

~/.../Grafik/mapengine >>> bass -i mapengine.asm -DHEIGHTMAP                                                                                                                                                                        
#
:0: warning: Macro 'MATH_MAKE_MULTAB' shadows global symbol square0_hi
#

(With the above case this is no actual problem -> it transports the exact same addresses throughout code.)

While kick introduced scopes to solve this I think there's actually a better way -> anonymous sections. Something like this:

!macro MY_MACRO(addr0, addr1, value0, value1)
; implies:
;     !section "__macro_<instance_identifier>", start=*
;     (<instance_identifier> is a placeholder for a unique id)
{
  lda #value0
  sta addr0

}

Btw. in combination with #11 it would also allow for "$" labels inside macros.

segfault on "Lambda" block

While assembling I stumbled upon a coredump situation:

~/.../Grafik/mapengine >>> bass -i macros/heightmap.asm -o DELETE_ME.prg -DHEIGHTMAP                                                                                                                                                                    ±[●●][bass]
* PARSING
Using cached AST
* PASS 1
Using cached AST
Using cached AST
zsh: segmentation fault (core dumped)  bass -I macros -i macros/heightmap.asm -o DELETE_ME.prg -DHEIGHTMAP

Here's a link to my work-branch so you can try for yourself. Note this is a work-in-progress - means the code still contains a lot of syntax and semantic errors.

unexpected behaviour for "!include"

Hey,
just porting a bigger project from kick assembler and it raised some questions on the include mechanism:

Docs state that files are always included relatively to the "current" file's path. The behavior seems to be different though and path is always relative to the "root" input file given in bass -i <file.asm> option.
- Is there an option to edit the include search path maybe so i could work around that?

The !include directive currently includes files multiple times. -> moved to #8

Cheers, Nils

LUA errors are not shown

Any error thrown by LUA code just causes the code to fail silently.

DoD:

LUA errors should be reported as an error, preferably with file and line.

Can newline be optional at EOT?

Currently bass errors out if no newline is given before EOF:

; no newline before EOF -> error

vs

; newline(s) before EOF -> ok

[request] symbol attributes

In some cases it can be helpful to define macro parameters read-only (const) and error out when trying a write operation. Here's a draft of what it could look like:

!macro m(foo:const, bar) {
  inc bar  ; ok: bar is not marked read-only
  
  ; a write "foo" would error out
  inc bar  ; error: bar is readonly
}

Also "assignments" could benefit from that:

value:const = 42

; same for local variables
label_0:
.value:const = 42

bug: off-by-one with negative int8 values

The following code produces off-by-one situations:

!org 0x1000

test_1:  ;results in 0x7f == 127 (vs expected 0xff)
  !test "int8 test with -1"
  lda #<(-1)
  !log "A: {A} (expected: 255)"
  !check A == 255

test_2:  ;results in 0x80 == -128 (vs expected 0x00)
  !test "int8 test with -0"
  lda #<(-0)
  !log "A: {A} (epxected: 0)"
  !check A == 0

[request] section labels

Can't a section also define a (global) label?

!section "math", start=$1000
math:  ; <-- redundant
  .func1: !fill 256, <some-function>
  .func2: !fill 256, <some-other-function>

Also a NoLabel=true option could be useful to disable the feature.

EDIT: Further it may be a good idea that labels become global to a section. Given the above example that means:

!section "math", start=$1000
  func1: !fill 256, <some-function>           ; <-- call: math.func1
  func2: !fill 256, <some-other-function>     ; <-- call: math.func2

[request] add commandline option to clear cache

For issues like #22 a --clear-cache option would be nice that deletes any file in the .basscache directory.

Also - if bass can assemble without a .basscache at all - a --no-cache option may be useful.

[request] output local labels in symbol table

Currently local symbols are not added to the symbol file (or stdout). A use case for this is a memory layout describing a static object:

!section "world", start=0x0, NoStore=true
world:  ; can we define a world[0]?
  ; rotation parameters
  .rmatrix: !fill 3*3, 0
  .rmatrix_size = *-1
  .rot_x: !byte 0
  .rot_y: !byte 0
  .rot_z: !byte 0
  ;…
  .size = *-world 
  .end = *-1

Symbol table output:

world = $0
;the local labels do not appear in output symbol table 
world.rot_rmatrix = $0
world.rot_x = $9
world.rot_y = $a
world.rot_z = $b
;…

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.