Jump to content
IGNORED

Developing a new language - ACUSOL


Pab

Recommended Posts

When run, the edit window of the compiler executable contains this skeleton for those who want a qu

MODULE ORG=$1F00

USES Print

CARD c

PROC MAIN

RETURN

The MODULE command, as a reminder, tells the compiler where in memory to put the code (and optionally variables) generated until the next MODULE is hit. The ORG statement says where to place the code. The optional VARIABLES statement will tell the compiler where to put variables for this section. If left out, variables will be allocated within the code as Action! does.

 

Addresses in banked RAM are represented by the memory location, a colon,. and the bank number (1-64 supported by compiler, but subject to actual RAM in the machine obviously). Bank 0 always refers to the "main" bank of a stock machine.

 

Examples: Compile placing code in main bank starting at $2000 and variables in main bank starting at $8000

MODULE ORG=$2000 VARIABLES=$8000

Compile both code and variables starting at $4000 in bank #2 of expanded memory.

MODULE ORG=$4000:2

Compile code beginning at $A000 (for cartridge use, for example) and variables starting at $4000 in bank #1.

MODULE ORG=$A000 VARIABLES=$4000:1

The USES PRINT statement will load the routines from PRINT.ACC at compile time. In the finished product, only routines needed will end up being compiled.

 

If there is a procedure called MAIN, it will be run after the program file is run by DOS. Thus the skeleton of a procedure.

Link to comment
Share on other sites

  • 2 weeks later...

Bit of a milestone reached tonight: objects appear to be functional. Fields can be assigned within or outside of the class, methods can be called and can return data. Still need to work on and test descendant types, and will hopefully have a much more elaborate example once I'm sure things are actually working properly.

MODULE ORG=$1F00

USES Print

CLASS TObject
  BYTE B
  BYTE E
  PROC Init
  BYTE FUNC Query
END

PROC TObject.Init
  B = 10
  E = $9B
RETURN

BYTE FUNC TObject.Query
  RESULT = B
RETURN

PROC MAIN
TObject T,U
BYTE x

  T.Init
  U.Init

  T.B = 35
  U.E = 100

  x = T.Query 

  Print("This should be 35: ")
  PrintBE(x)
  Print("This should be 10: ")
  PrintBE(U.B)
  Print("This should be 100: ")
  PrintBE(U.E)
  Print("This should be 155: ")
  PrintBE(T.E)

RETURN

Right now things are a little kludgy when assigning values to fields from within an object method. When the compiler defines a class, it keeps track of all of the fields within the class and assigns each of them a "class offset" value, pointing to how many bytes into the class the field we want is. In my example program above, the class offset of "B" in a TObject instance is 0 (it's at the base address of the instance) and "E" has an offset of 1 (one byte higher than the base). If B had been a CARD, then E's offset would have been 2. And so on.

 

When a field is accessed outside of the class's own methods, the compiler does the heavy lifting. In this program, "U" is located at $2289. When we assign 100 to U.E, the compiler knows that since E's offset is 1, so the variable we are accessing is at $228A. Simple operation, two opcodes.

23B7: A9 64             LDA #$64
23B9: 8D 8A 23          STA $238A

When a field is accessed within the method, however, we don't know at compile time where the addresses we are going to be working with are. When an object method is called, the first argument (hidden to the user) is always a pointer to the instance we are going to be working with. To access the field, the machine adds the offset to the instance address via the micro-runtime's 16-bit addition routine.

22D6: AD 96 22          LDA $2296
22D9: 85 CB             STA $CB
22DB: AD 97 22          LDA $2297
22DE: 85 CC             STA $CC
22E0: A9 01             LDA #$01
22E2: 85 CD             STA $CD
22E4: A9 00             LDA #$00
22E6: 85 CE             STA $CE
22E8: 20 15 20          JSR $2015

Not very elegant to say the least. Can't yet think of a more efficient way.

post-12895-0-65413900-1428194854_thumb.gif

  • Like 1
Link to comment
Share on other sites

Got arrays of objects to work this morning, and made a tweak to the definition of hard-addressed procedures. Then wrote a long post about something I'd done by accident then decided to keep in place before I thought "why are you doing that?" So I went and fixed the accident. :)

 

I'm adding a compiler flag (probably "ACTIONARGS") to decide whether or not to load the first three bytes' worth of arguments into registers. Yeah, it only takes 6 bytes of code and a few machine cycles to do that, but why waste the time on every procedure call if you don't need to? That way you can just turn the flag on for procedure definitions or modules where you need them loaded.

 

Remember also that there are already pseudovariables for the three hardware registers already in the language. Most programmers would probably want to do something like

6502_X = $10
CIOV

than

CIOV(0,$10)

as the resulting code will be much tighter. (It would compile to LDX #10/JSR CIOV, very tight and fast.)

Edited by Pab
  • Like 1
Link to comment
Share on other sites

Another example, which I mainly used to test class arrays. A very unnecessarily roundabout "Hello World" program.

MODULE ORG=$1F00

CLASS TIOCB
   BYTE ID
   BYTE Number
   BYTE Command
   BYTE Status
   CARD Address
   CARD PutOne
   CARD Length
   BYTE ARRAY Aux[6]
   PROC Run(BYTE a,x)
END

// Array pointing to IOCB's
// in RAM

TIOCB ARRAY IOCB[8] = $340

// String in fixed spot since
// I don't have pointers fully
// functional yet.

STRING s[128] = $0580

// Pass args in registers

DEFINE ACTIONARGS

PROC CIOV = $E456(BYTE a,x)

UNDEFINE ACTIONARGS

// End code using ActionArgs

PROC TIOCB.Run(BYTE a,x)
  CIOV(a,x)
RETURN

PROC MAIN
  s = "Hello World"
  IOCB[0].Command = 11
  IOCB[0].Address = $581
  IOCB[0].Length = 11
  IOCB[0].Run(0,0)
  IOCB[0].Length = 0
  IOCB[0].Run(155,0)
RETURN

post-12895-0-21299400-1428266344_thumb.gif

Link to comment
Share on other sites

Since I wanted to start doing some more elaborate programming (and figured some of you out there would too) to test this thing as I develop, I've spent the last couple of days working on I/O routines for the runtime package. I'll share them when I upload the latest build.

 

Also put into place (sort of needed it if disk I/O is in the offing) some basic error handling in the runtime. New additions to the language's page 0 memory map include:

 

$C5 - DEVICE - Default device #

$C6 - LASTERROR - Error returned by CIO or other routines

$C7/$C8 - ERRORVEC - Pointer to a routine to use in place of built-in error handling

 

Also, like Action!, an EOF is NOT treated as an error, but just sets a flag. The end-of-file status can be checked in the boolean array EOF[x]

Link to comment
Share on other sites

You guys are right. There's really no benefit to using zero page for those locations since indirect jump (which is used with the error vector) needs a two byte argument anyhow, and since LastError and Device will be called so infrequently that the byte saved in each reference just isn't worth tying up those locations. Will do a little rewriting to move those values into ones allocated dynamically when using the I/O runtime.

 

That leaves the only locations needed by the language as $A0-$AF and $C9-$D0. I only use the FP locations for scratch memory, such as values returned from the micro-runtime routines, so nothing will be lost if we choose to fully implement floats.

 

I'm thinking about the possibilities of implementing 32-bit LONG variables, which might require more locations. Right now the micro-runtime routines use CB/CC and CD/CE for the operands, with CF and D0 being used generally for bank numbers when referring to locations in banked RAM. If I need to add 32 bit math, one operand would have to be from $CB-CE. I guess the second operand could be $CF-$D2, since bank numbers would never be needed in 32 bit operations. That way the result could be passed in $D4-$D7.

 

I think in the long run we'd be better off implementing 32-bits than floats. Not that one rules out the other. Just implementing floats is turning out to be a big pain in the ass and the time I would invest in it would be better spent on LONGs.

Link to comment
Share on other sites

Here's an interesting question. About to write the RTL code for the XIO command, I was reminded of the weird syntax Action! used for its XIO routine:

XIO(device,0,command,aux1,aux2,filespec)

What was with the extra byte (which apparently was unnecessary because they said to just use a 0 there) between the device number and command? And other than backwards compatibility with Action! is there any reason to keep it?

 

The one thing I can think of is that since Action! passed the first three bytes in the registers, this kept the X register free and put the command in the Y register. This way the routine could just ASL A four times, TAX, and STY ICCOM and not have to do anything with X. But if so, it's a kludgy way of doing things.

Edited by Pab
Link to comment
Share on other sites

This is really coming along well. I've not used it before because it has been very much work in progress and thought that I might hit a few issues. It is looking like that a lot of those will be gone soon and there's lots of extra functionality.

 

Can I ask, will there be a manual enclosed with this?

Link to comment
Share on other sites

As for the public beta, I'm not sure there will really be such a thing. The idea at this point is to build a bootstrap compiler, with which I (and hopefully some volunteers) can write a native compiler that will run on the Atari that anyone can use. I'm going to keep putting out alpha versions here for people to look at and play around with. One will be coming tomorrow if all goes well.

 

As for the manual, I'll put together a language reference and tutorial, and docs for the RTL, but a full manual will probably have to wait until we're well into the native compiler.

Link to comment
Share on other sites

One thing I wanted to get fully functional before I put out the latest build, just because it was the first feature request I remember seeing that I knew I could get functional in a hurry: support for interrupts.

 

It's now possible to write a procedure to be used as an interrupt simply by replacing the PROC keyword with INTERRUPT. Doing this will add code to push the registers onto the stack, and when a RETURN is reached, the registers will be popped off of the stack and an RTI used to return instead of RTS.

 

Example program, quick and dirty DLI.

MODULE ORG=$1F00

CARD DLIVector=$200
CARD DLAddress=$230
BYTE InterruptEnable=$D40E
BYTE CH=$2FC

BYTE ARRAY DisplayList[0]
[$70 $70 $70
 $42 $40 $9C
 $02 $02 $02
 $02 $02 $02
 $02 $02 $82
 $02 $02 $02
 $02 $02 $02
 $02 $02 $02
 $02 $02 $02
 $02 $02 $41 
 DisplayList]

INTERRUPT ColorShift
BYTE COLPF2=$D018
  COLPF2=$38
RETURN

PROC MAIN
CARD OldDisplayList

// Stash the old DL address

  OldDisplayList = DLAddress

// Set our interrupt vector

  DLIVector = @ColorShift

// Zap in our new display list

  DLAddress = @DisplayList

// Enable Interrupt

  InterruptEnable = 192  

// Wait for a key

  CH = $FF
  WHILE CH=$FF DO OD

// Go back to normal.

  InterruptEnable = 64
  DLAddress = OldDisplayList
  CH = $FF

RETURN

post-12895-0-67935700-1428524484_thumb.gif

Edited by Pab
  • Like 2
Link to comment
Share on other sites

For your inspection and amusement, the latest build. I'm working on pointers at the moment, but they're giving me a headache so I thought I'd put out what I had.


WHAT DOESN'T WORK (yet):


* Pointers, for the most part.

* Arrays within classes. Working on this, too. Need to test some stuff.

* Error vector for custom error handling. Being rewritten to not require page zero location.

* FLOATs. Still debating the need for them.

* STRING FUNCs

* Probably dozens of new bugs I added in but haven't detected yet. Sigh.


Changelog for this version:



GUI:

====

* Added ability to load/save source files.

* Layout changes.


COMPILER:

=========

* Added object support.

* Added ACTIONARGS flag to pass arguments in registers.

* Fixed bug in assigning address of fixed location procedure.

* Fixed bug in parsing multiple arguments in procedure calls.

* Finalized support for INTeger variables (signed 16-bit)

* Added !BANKPEEK, !BANKPOKE, and !BANKCOPY labels for ML code.

* Fixed bug where function calls in assignments would skip over arguments.

* Bug: Bank initialization code was never run unless code was placed in a bank. For the time being, the bank initialization routine is ALWAYS the first segment of a file, at least until we have two pass compilation and will know whether or not we need banked support.

* Fixed bug in storing the address of a variable or procedure in another variable. (a = @b). If assigning to a CARD, the result will be the address (no bank information) of the variable. If assigning to a pointer, banking information will be included.


RTL:

====

* Deprecated PRINT.ACC

* New unit IO.ACC includes the following calls:



PROC StrC(CARD c,STRING POINTER s)
PROC StrB(BYTE b,STRING POINTER s)
PROC StrI(INT i,STRING POINTER s)
PROC XIO(BYTE d,scrap,c,m,a STRING f)
PROC Open(BYTE d STRING f BYTE m,a)
PROC Close(BYTE d)
BYTE FUNC GetD(BYTE d)
BYTE FUNC Get(BYTE d)
PROC PutD(BYTE ICB,a)
PROC PrintD(BYTE ICB, STRING s)
PROC PrintDE(BYTE ICB, STRING s)
PROC Print(STRING s)
PROC PrintE(STRING POINTER s)
PROC Put(BYTE b)
PROC PrintC(CARD c)
PROC PrintCE(CARD c)
PROC PrintID(BYTE d INT i)
PROC PrintI(INT i)
PROC PrintIDE(BYTE d INT i)
PROC PrintBD(BYTE d,b)
PROC PrintB(BYTE b)
PROC PrintBE(BYTE b)
PROC PrintBDE(BYTE d,b)
CLASS TIOCB
BOOL ARRAY EOF[8]
BYTE device
BYTE LastError
TIOCB ARRAY IOCB[8] = $340


AccomplishCompiler 0-2-0-14.zip

Edited by Pab
  • Like 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...