Start a Modula-2 experiment

This commit is contained in:
2024-02-15 15:13:47 +01:00
parent 0d3453e7a9
commit 3fda793f74
26 changed files with 591 additions and 3106 deletions

2
.gitignore vendored
View File

@@ -1,3 +1,3 @@
/.dub/ a.out
/dub.selections.json /dub.selections.json
/build/ /build/

37
README
View File

@@ -1,37 +0,0 @@
# Elna programming language
Elna compiles simple mathematical operations to machine code.
The compiled program returns the result of the operation.
## File extension
.elna
## Grammar PL/0
program = block "." ;
block = [ "const" ident "=" number {"," ident "=" number} ";"]
[ "var" ident {"," ident} ";"]
{ "procedure" ident ";" block ";" } statement ;
statement = [ ident ":=" expression | "call" ident
| "?" ident | "!" expression
| "begin" statement {";" statement } "end"
| "if" condition "then" statement
| "while" condition "do" statement ];
condition = "odd" expression |
expression ("="|"#"|"<"|"<="|">"|">=") expression ;
expression = [ "+"|"-"] term { ("+"|"-") term};
term = factor {("*"|"/") factor};
factor = ident | number | "(" expression ")";
## Operations
"!" - Write a line.
"?" - Read user input.
"odd" - The only function, returns whether a number is odd.

63
README.md Normal file
View File

@@ -0,0 +1,63 @@
# Elna programming language
Elna is a simple, imperative, low-level programming language.
It is intendet to accompany other languages in the areas, where a high-level
language doesn't fit well. It is also supposed to be an intermediate
representation for a such high-level hypothetical programming language.
## File extension
.elna
## Current implementation
This repository contains a GCC frontend for Elna. After finishing the frontend
I'm planning to rewrite the compiler in Elna itself with its own backend and
a hand-written parser. So GCC gives a way to have a simple bootstrap compiler
and a possbility to compile Elna programs for different platforms.
## Grammar
program = block "." ;
block = [ "const" ident "=" number {"," ident "=" number} ";"]
[ "var" ident {"," ident} ";"]
{ "procedure" ident ";" block ";" } statement ;
statement = [ ident ":=" expression | "call" ident
| "?" ident | "!" expression
| "begin" statement {";" statement } "end"
| "if" condition "then" statement
| "while" condition "do" statement ];
condition = "odd" expression |
expression ("="|"#"|"<"|"<="|">"|">=") expression ;
expression = [ "+"|"-"] term { ("+"|"-") term};
term = factor {("*"|"/") factor};
factor = ident | number | "(" expression ")";
## Build
The frontend requires GCC 14.2.0 (not tested with other versions).
Download the GCC source. Copy the contents of this repository into `gcc/elna`
inside GCC. Finally build GCC enabling the frontend with
`--enable-languages=c,c++,elna`. After the installation the compiler can be
invoked with `$prefix/bin/gelna`.
There is also a `Rakefile` that downloads, builds and installs GCC into the
`./build/` subdirectory. The `Rakefile` assumes that ruby and rake, as well as
all GCC dependencies are already available in the system. It works under Linux
and Mac OS. In the latter case GCC is patched with the patches used by Homebrew
(official GCC doesn't support Apple silicon targets). Invoke with
```sh
rake boot
```
See `rake -T` for more tasks. The GCC source is under `build/tools`. The
installation path is `build/host/install`.

View File

@@ -21,13 +21,13 @@ CLEAN.include '.dub'
rule(/build\/riscv\/[^\/\.]+$/ => ->(file) { test_for_out(file, '.o') }) do |t| rule(/build\/riscv\/[^\/\.]+$/ => ->(file) { test_for_out(file, '.o') }) do |t|
sh '/opt/riscv/bin/riscv32-unknown-elf-ld', sh '/opt/riscv/bin/riscv32-unknown-elf-ld',
'-o', t.name, '-o', t.name,
'-L/opt/riscv/lib/gcc/riscv32-unknown-elf/11.1.0', '-L/opt/riscv/lib/gcc/riscv32-unknown-elf/13.2.0/',
'-L/opt/riscv/riscv32-unknown-elf/lib', '-L/opt/riscv/riscv32-unknown-elf/lib',
'/opt/riscv/riscv32-unknown-elf/lib/crt0.o', '/opt/riscv/riscv32-unknown-elf/lib/crt0.o',
'/opt/riscv/lib/gcc/riscv32-unknown-elf/11.1.0/crtbegin.o', '/opt/riscv/lib/gcc/riscv32-unknown-elf/13.2.0/crtbegin.o',
t.source, t.source,
'--start-group', '-lgcc', '-lc', '-lgloss', '--end-group', '--start-group', '-lgcc', '-lc', '-lgloss', '--end-group',
'/opt/riscv/lib/gcc/riscv32-unknown-elf/11.1.0/crtend.o' '/opt/riscv/lib/gcc/riscv32-unknown-elf/13.2.0/crtend.o'
end end
rule(/build\/riscv\/.+\.o$/ => ->(file) { test_for_object(file, '.eln') }) do |t| rule(/build\/riscv\/.+\.o$/ => ->(file) { test_for_object(file, '.eln') }) do |t|
@@ -36,7 +36,7 @@ rule(/build\/riscv\/.+\.o$/ => ->(file) { test_for_object(file, '.eln') }) do |t
end end
file BINARY => SOURCES do |t| file BINARY => SOURCES do |t|
sh({ 'DFLAGS' => (DFLAGS * ' ') }, 'dub', 'build', '--compiler=gdc-12') sh({ 'DFLAGS' => (DFLAGS * ' ') }, 'dub', 'build', '--compiler=gdc')
end end
task default: BINARY task default: BINARY
@@ -55,6 +55,7 @@ task test: BINARY do
if test.include? '/riscv/' if test.include? '/riscv/'
spike = [ spike = [
'/opt/riscv/bin/spike', '/opt/riscv/bin/spike',
'--isa=RV32IMAC',
'/opt/riscv/riscv32-unknown-elf/bin/pk', '/opt/riscv/riscv32-unknown-elf/bin/pk',
test test
] ]

522
compiler.mod Normal file
View File

@@ -0,0 +1,522 @@
MODULE Compiler;
FROM Terminal IMPORT WriteString, WriteLn;
TYPE
(*
Classification table assigns each possible character to a group (class). All
characters of the same group a handled equivalently.
Classification:
*)
TransitionClass = (
transitionClassInvalid,
transitionClassDigit,
transitionClassCharacter,
transitionClassSpace,
transitionClassColon,
transitionClassEquals,
transitionClassLeftParen,
transitionClassRightParen,
transitionClassAsterisk,
transitionClassUnderscore,
transitionClassSingle,
transitionClassHex,
transitionClassZero,
transitionClassX,
transitionClassEof,
transitionClassDot,
transitionClassMinus,
transitionClassQuote,
transitionClassGreater,
transitionClassLess,
transitionClassOther
);
TransitionState = (
transitionStateStart,
transitionStateColon,
transitionStateIdentifier,
transitionStateDecimal,
transitionStateGreater,
transitionStateMinus,
transitionStateLeftParen,
transitionStateLess,
transitionStateHexadecimal,
transitionStateComment,
transitionStateClosingComment,
transitionStateString,
transitionStateLeadingZero,
transitionStateHexadecimalPrefix,
transitionStateEnd
);
TransitionAction = PROCEDURE();
Transition = RECORD
Action: TransitionAction;
NextState: TransitionState
END;
VAR
Classification: ARRAY[1..128] OF TransitionClass;
Transitions: ARRAY[0..MAX(TransitionState)] OF ARRAY[0..MAX(TransitionClass)] OF Transition;
PROCEDURE InitializeClassification();
BEGIN
Classification[1] := transitionClassEof; (* NUL *)
Classification[2] := transitionClassInvalid; (* SOH *)
Classification[3] := transitionClassInvalid; (* STX *)
Classification[4] := transitionClassInvalid; (* ETX *)
Classification[5] := transitionClassInvalid; (* EOT *)
Classification[6] := transitionClassInvalid; (* EMQ *)
Classification[7] := transitionClassInvalid; (* ACK *)
Classification[8] := transitionClassInvalid; (* BEL *)
Classification[9] := transitionClassInvalid; (* BS *)
Classification[10] := transitionClassSpace; (* HT *)
Classification[11] := transitionClassSpace; (* LF *)
Classification[12] := transitionClassInvalid; (* VT *)
Classification[13] := transitionClassInvalid; (* FF *)
Classification[14] := transitionClassSpace; (* CR *)
Classification[15] := transitionClassInvalid; (* SO *)
Classification[16] := transitionClassInvalid; (* SI *)
Classification[17] := transitionClassInvalid; (* DLE *)
Classification[18] := transitionClassInvalid; (* DC1 *)
Classification[19] := transitionClassInvalid; (* DC2 *)
Classification[20] := transitionClassInvalid; (* DC3 *)
Classification[21] := transitionClassInvalid; (* DC4 *)
Classification[22] := transitionClassInvalid; (* NAK *)
Classification[23] := transitionClassInvalid; (* SYN *)
Classification[24] := transitionClassInvalid; (* ETB *)
Classification[25] := transitionClassInvalid; (* CAN *)
Classification[26] := transitionClassInvalid; (* EM *)
Classification[27] := transitionClassInvalid; (* SUB *)
Classification[28] := transitionClassInvalid; (* ESC *)
Classification[29] := transitionClassInvalid; (* FS *)
Classification[30] := transitionClassInvalid; (* GS *)
Classification[31] := transitionClassInvalid; (* RS *)
Classification[32] := transitionClassInvalid; (* US *)
Classification[33] := transitionClassSpace; (* Space *)
Classification[34] := transitionClassSingle; (* ! *)
Classification[35] := transitionClassQuote; (* " *)
Classification[36] := transitionClassOther; (* # *)
Classification[37] := transitionClassOther; (* $ *)
Classification[38] := transitionClassSingle; (* % *)
Classification[39] := transitionClassSingle; (* & *)
Classification[40] := transitionClassQuote; (* ' *)
Classification[41] := transitionClassLeftParen; (* ( *)
Classification[42] := transitionClassRightParen; (* ) *)
Classification[43] := transitionClassAsterisk; (* * *)
Classification[44] := transitionClassSingle; (* + *)
Classification[45] := transitionClassSingle; (* , *)
Classification[46] := transitionClassMinus; (* - *)
Classification[47] := transitionClassDot; (* . *)
Classification[48] := transitionClassSingle; (* / *)
Classification[49] := transitionClassZero; (* 0 *)
Classification[50] := transitionClassDigit; (* 1 *)
Classification[51] := transitionClassDigit; (* 2 *)
Classification[52] := transitionClassDigit; (* 3 *)
Classification[53] := transitionClassDigit; (* 4 *)
Classification[54] := transitionClassDigit; (* 5 *)
Classification[55] := transitionClassDigit; (* 6 *)
Classification[56] := transitionClassDigit; (* 7 *)
Classification[57] := transitionClassDigit; (* 8 *)
Classification[58] := transitionClassDigit; (* 9 *)
Classification[59] := transitionClassColon; (* : *)
Classification[60] := transitionClassSingle; (* ; *)
Classification[61] := transitionClassLess; (* < *)
Classification[62] := transitionClassEquals; (* = *)
Classification[63] := transitionClassGreater; (* > *)
Classification[64] := transitionClassOther; (* ? *)
Classification[65] := transitionClassSingle; (* @ *)
Classification[66] := transitionClassCharacter; (* A *)
Classification[67] := transitionClassCharacter; (* B *)
Classification[68] := transitionClassCharacter; (* C *)
Classification[69] := transitionClassCharacter; (* D *)
Classification[70] := transitionClassCharacter; (* E *)
Classification[71] := transitionClassCharacter; (* F *)
Classification[72] := transitionClassCharacter; (* G *)
Classification[73] := transitionClassCharacter; (* H *)
Classification[74] := transitionClassCharacter; (* I *)
Classification[75] := transitionClassCharacter; (* J *)
Classification[76] := transitionClassCharacter; (* K *)
Classification[77] := transitionClassCharacter; (* L *)
Classification[78] := transitionClassCharacter; (* M *)
Classification[79] := transitionClassCharacter; (* N *)
Classification[80] := transitionClassCharacter; (* O *)
Classification[81] := transitionClassCharacter; (* P *)
Classification[82] := transitionClassCharacter; (* Q *)
Classification[83] := transitionClassCharacter; (* R *)
Classification[84] := transitionClassCharacter; (* S *)
Classification[85] := transitionClassCharacter; (* T *)
Classification[86] := transitionClassCharacter; (* U *)
Classification[67] := transitionClassCharacter; (* V *)
Classification[88] := transitionClassCharacter; (* W *)
Classification[89] := transitionClassCharacter; (* X *)
Classification[90] := transitionClassCharacter; (* Y *)
Classification[91] := transitionClassCharacter; (* Z *)
Classification[92] := transitionClassSingle; (* [ *)
Classification[93] := transitionClassOther; (* \ *)
Classification[94] := transitionClassSingle; (* ] *)
Classification[95] := transitionClassSingle; (* ^ *)
Classification[96] := transitionClassUnderscore; (* _ *)
Classification[97] := transitionClassOther; (* ` *)
Classification[98] := transitionClassHex; (* a *)
Classification[99] := transitionClassHex; (* b *)
Classification[100] := transitionClassHex; (* c *)
Classification[101] := transitionClassHex; (* d *)
Classification[102] := transitionClassHex; (* e *)
Classification[103] := transitionClassHex; (* f *)
Classification[104] := transitionClassCharacter; (* g *)
Classification[105] := transitionClassCharacter; (* h *)
Classification[106] := transitionClassCharacter; (* i *)
Classification[107] := transitionClassCharacter; (* j *)
Classification[108] := transitionClassCharacter; (* k *)
Classification[109] := transitionClassCharacter; (* l *)
Classification[110] := transitionClassCharacter; (* m *)
Classification[111] := transitionClassCharacter; (* n *)
Classification[112] := transitionClassCharacter; (* o *)
Classification[113] := transitionClassCharacter; (* p *)
Classification[114] := transitionClassCharacter; (* q *)
Classification[115] := transitionClassCharacter; (* r *)
Classification[116] := transitionClassCharacter; (* s *)
Classification[117] := transitionClassCharacter; (* t *)
Classification[118] := transitionClassCharacter; (* u *)
Classification[119] := transitionClassCharacter; (* v *)
Classification[120] := transitionClassCharacter; (* w *)
Classification[121] := transitionClassX; (* x *)
Classification[122] := transitionClassCharacter; (* y *)
Classification[123] := transitionClassCharacter; (* z *)
Classification[124] := transitionClassOther; (* { *)
Classification[125] := transitionClassSingle; (* | *)
Classification[126] := transitionClassOther; (* } *)
Classification[127] := transitionClassSingle; (* ~ *)
Classification[128] := transitionClassInvalid (* DEL *)
END InitializeClassification;
(* 0x00. No action. *)
PROCEDURE TransitionActionNo();
BEGIN
END TransitionActionNo;
(* 0x01. Accumulate action. *)
PROCEDURE TransitionActionAccumulate();
BEGIN
END TransitionActionAccumulate;
(* 0x02. Print action. *)
PROCEDURE TransitionActionPrint();
BEGIN
END TransitionActionPrint;
(* 0x03. Skip action. *)
PROCEDURE TransitionActionSkip();
BEGIN
END TransitionActionSkip;
(* 0x04. Delimited string action. *)
PROCEDURE TransitionActionDelimited();
BEGIN
END TransitionActionDelimited;
(* 0x05. Finalize identifier action. *)
PROCEDURE TransitionActionFinalize();
BEGIN
END TransitionActionFinalize;
(* 0x06. Single character symbol action. *)
PROCEDURE TransitionActionSingle();
BEGIN
END TransitionActionSingle;
(* 0x07. An action for symbols containing multiple characters. *)
PROCEDURE TransitionActionComposite();
BEGIN
END TransitionActionComposite;
(* 0x08. Integer action. *)
PROCEDURE TransitionActionInteger();
BEGIN
END TransitionActionInteger;
PROCEDURE SetDefaultTransition(currentState: TransitionState; DefaultAction: TransitionAction; NextState: TransitionState);
VAR DefaultTransition: Transition;
BEGIN
DefaultTransition.Action := DefaultAction;
DefaultTransition.NextState := NextState;
Transitions[ORD(currentState)][ORD(transitionClassInvalid)] := DefaultTransition;
Transitions[ORD(currentState)][ORD(transitionClassDigit)] := DefaultTransition;
Transitions[ORD(currentState)][ORD(transitionClassCharacter)] := DefaultTransition;
Transitions[ORD(currentState)][ORD(transitionClassSpace)] := DefaultTransition;
Transitions[ORD(currentState)][ORD(transitionClassColon)] := DefaultTransition;
Transitions[ORD(currentState)][ORD(transitionClassEquals)] := DefaultTransition;
Transitions[ORD(currentState)][ORD(transitionClassLeftParen)] := DefaultTransition;
Transitions[ORD(currentState)][ORD(transitionClassRightParen)] := DefaultTransition;
Transitions[ORD(currentState)][ORD(transitionClassAsterisk)] := DefaultTransition;
Transitions[ORD(currentState)][ORD(transitionClassUnderscore)] := DefaultTransition;
Transitions[ORD(currentState)][ORD(transitionClassSingle)] := DefaultTransition;
Transitions[ORD(currentState)][ORD(transitionClassHex)] := DefaultTransition;
Transitions[ORD(currentState)][ORD(transitionClassZero)] := DefaultTransition;
Transitions[ORD(currentState)][ORD(transitionClassX)] := DefaultTransition;
Transitions[ORD(currentState)][ORD(transitionClassEof)] := DefaultTransition;
Transitions[ORD(currentState)][ORD(transitionClassDot)] := DefaultTransition;
Transitions[ORD(currentState)][ORD(transitionClassMinus)] := DefaultTransition;
Transitions[ORD(currentState)][ORD(transitionClassQuote)] := DefaultTransition;
Transitions[ORD(currentState)][ORD(transitionClassGreater)] := DefaultTransition;
Transitions[ORD(currentState)][ORD(transitionClassLess)] := DefaultTransition;
Transitions[ORD(currentState)][ORD(transitionClassOther)] := DefaultTransition;
END SetDefaultTransition;
(*
* The transition table describes transitions from one state to another, given
* a symbol (character class).
*
* The table has m rows and n columns, where m is the amount of states and n is
* the amount of classes. So given the current state and a classified character
* the table can be used to look up the next state.
*
* Each cell is a word long.
* - The least significant byte of the word is a row number (beginning with 0).
* It specifies the target state. "ff" means that this is an end state and no
* transition is possible.
* - The next byte is the action that should be performed when transitioning.
* For the meaning of actions see labels in the lex_next function, which
* handles each action.
*)
PROCEDURE InitializeTransitions();
BEGIN
(* Start state. *)
Transitions[ORD(transitionStateStart)][ORD(transitionClassInvalid)].Action := TransitionActionNo;
Transitions[ORD(transitionStateStart)][ORD(transitionClassInvalid)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateStart)][ORD(transitionClassDigit)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateStart)][ORD(transitionClassDigit)].NextState := transitionStateDecimal;
Transitions[ORD(transitionStateStart)][ORD(transitionClassCharacter)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateStart)][ORD(transitionClassCharacter)].NextState := transitionStateIdentifier;
Transitions[ORD(transitionStateStart)][ORD(transitionClassSpace)].Action := TransitionActionSkip;
Transitions[ORD(transitionStateStart)][ORD(transitionClassSpace)].NextState := transitionStateStart;
Transitions[ORD(transitionStateStart)][ORD(transitionClassColon)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateStart)][ORD(transitionClassColon)].NextState := transitionStateColon;
Transitions[ORD(transitionStateStart)][ORD(transitionClassEquals)].Action := TransitionActionSingle;
Transitions[ORD(transitionStateStart)][ORD(transitionClassEquals)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateStart)][ORD(transitionClassLeftParen)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateStart)][ORD(transitionClassLeftParen)].NextState := transitionStateLeftParen;
Transitions[ORD(transitionStateStart)][ORD(transitionClassRightParen)].Action := TransitionActionSingle;
Transitions[ORD(transitionStateStart)][ORD(transitionClassRightParen)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateStart)][ORD(transitionClassAsterisk)].Action := TransitionActionSingle;
Transitions[ORD(transitionStateStart)][ORD(transitionClassAsterisk)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateStart)][ORD(transitionClassUnderscore)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateStart)][ORD(transitionClassUnderscore)].NextState := transitionStateIdentifier;
Transitions[ORD(transitionStateStart)][ORD(transitionClassSingle)].Action := TransitionActionSingle;
Transitions[ORD(transitionStateStart)][ORD(transitionClassSingle)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateStart)][ORD(transitionClassHex)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateStart)][ORD(transitionClassHex)].NextState := transitionStateIdentifier;
Transitions[ORD(transitionStateStart)][ORD(transitionClassZero)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateStart)][ORD(transitionClassZero)].NextState := transitionStateLeadingZero;
Transitions[ORD(transitionStateStart)][ORD(transitionClassX)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateStart)][ORD(transitionClassX)].NextState := transitionStateIdentifier;
Transitions[ORD(transitionStateStart)][ORD(transitionClassEof)].Action := TransitionActionNo;
Transitions[ORD(transitionStateStart)][ORD(transitionClassEof)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateStart)][ORD(transitionClassDot)].Action := TransitionActionSingle;
Transitions[ORD(transitionStateStart)][ORD(transitionClassDot)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateStart)][ORD(transitionClassMinus)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateStart)][ORD(transitionClassMinus)].NextState := transitionStateMinus;
Transitions[ORD(transitionStateStart)][ORD(transitionClassQuote)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateStart)][ORD(transitionClassQuote)].NextState := transitionStateString;
Transitions[ORD(transitionStateStart)][ORD(transitionClassGreater)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateStart)][ORD(transitionClassGreater)].NextState := transitionStateGreater;
Transitions[ORD(transitionStateStart)][ORD(transitionClassLess)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateStart)][ORD(transitionClassLess)].NextState := transitionStateLess;
Transitions[ORD(transitionStateStart)][ORD(transitionClassOther)].Action := TransitionActionNo;
Transitions[ORD(transitionStateStart)][ORD(transitionClassOther)].NextState := transitionStateEnd;
(* Colon state. *)
SetDefaultTransition(transitionStateColon, TransitionActionPrint, transitionStateEnd);
Transitions[ORD(transitionStateColon)][ORD(transitionClassEquals)].Action := TransitionActionComposite;
Transitions[ORD(transitionStateColon)][ORD(transitionClassEquals)].NextState := transitionStateEnd;
(* Identifier state. *)
SetDefaultTransition(transitionStateIdentifier, TransitionActionFinalize, transitionStateEnd);
Transitions[ORD(transitionStateIdentifier)][ORD(transitionClassDigit)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateIdentifier)][ORD(transitionClassDigit)].NextState := transitionStateIdentifier;
Transitions[ORD(transitionStateIdentifier)][ORD(transitionClassCharacter)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateIdentifier)][ORD(transitionClassCharacter)].NextState := transitionStateIdentifier;
Transitions[ORD(transitionStateIdentifier)][ORD(transitionClassUnderscore)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateIdentifier)][ORD(transitionClassUnderscore)].NextState := transitionStateIdentifier;
Transitions[ORD(transitionStateIdentifier)][ORD(transitionClassHex)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateIdentifier)][ORD(transitionClassHex)].NextState := transitionStateIdentifier;
Transitions[ORD(transitionStateIdentifier)][ORD(transitionClassZero)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateIdentifier)][ORD(transitionClassZero)].NextState := transitionStateIdentifier;
Transitions[ORD(transitionStateIdentifier)][ORD(transitionClassX)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateIdentifier)][ORD(transitionClassX)].NextState := transitionStateIdentifier;
(* Decimal state. *)
SetDefaultTransition(transitionStateDecimal, TransitionActionInteger, transitionStateEnd);
Transitions[ORD(transitionStateDecimal)][ORD(transitionClassDigit)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateDecimal)][ORD(transitionClassDigit)].NextState := transitionStateDecimal;
Transitions[ORD(transitionStateDecimal)][ORD(transitionClassCharacter)].Action := TransitionActionNo;
Transitions[ORD(transitionStateDecimal)][ORD(transitionClassCharacter)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateDecimal)][ORD(transitionClassUnderscore)].Action := TransitionActionNo;
Transitions[ORD(transitionStateDecimal)][ORD(transitionClassUnderscore)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateDecimal)][ORD(transitionClassHex)].Action := TransitionActionNo;
Transitions[ORD(transitionStateDecimal)][ORD(transitionClassHex)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateDecimal)][ORD(transitionClassZero)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateDecimal)][ORD(transitionClassZero)].NextState := transitionStateDecimal;
Transitions[ORD(transitionStateDecimal)][ORD(transitionClassX)].Action := TransitionActionNo;
Transitions[ORD(transitionStateDecimal)][ORD(transitionClassX)].NextState := transitionStateEnd;
(* Greater state. *)
SetDefaultTransition(transitionStateGreater, TransitionActionPrint, transitionStateEnd);
Transitions[ORD(transitionStateGreater)][ORD(transitionClassEquals)].Action := TransitionActionDelimited;
Transitions[ORD(transitionStateGreater)][ORD(transitionClassEquals)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateGreater)][ORD(transitionClassGreater)].Action := TransitionActionDelimited;
Transitions[ORD(transitionStateGreater)][ORD(transitionClassGreater)].NextState := transitionStateEnd;
(* Minus state. *)
SetDefaultTransition(transitionStateGreater, TransitionActionSingle, transitionStateEnd);
Transitions[ORD(transitionStateMinus)][ORD(transitionClassGreater)].Action := TransitionActionDelimited;
Transitions[ORD(transitionStateMinus)][ORD(transitionClassGreater)].NextState := transitionStateEnd;
(* Left paren state. *)
SetDefaultTransition(transitionStateLeftParen, TransitionActionSingle, transitionStateEnd);
Transitions[ORD(transitionStateLeftParen)][ORD(transitionClassAsterisk)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateLeftParen)][ORD(transitionClassAsterisk)].NextState := transitionStateComment;
(* Less state. *)
SetDefaultTransition(transitionStateLess, TransitionActionSingle, transitionStateEnd);
Transitions[ORD(transitionStateLess)][ORD(transitionClassLess)].Action := TransitionActionDelimited;
Transitions[ORD(transitionStateLess)][ORD(transitionClassLess)].NextState := transitionStateEnd;
(* Hexadecimal after 0x. *)
SetDefaultTransition(transitionStateHexadecimal, TransitionActionInteger, transitionStateEnd);
Transitions[ORD(transitionStateHexadecimal)][ORD(transitionClassDigit)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateHexadecimal)][ORD(transitionClassDigit)].NextState := transitionStateHexadecimal;
Transitions[ORD(transitionStateHexadecimal)][ORD(transitionClassCharacter)].Action := TransitionActionNo;
Transitions[ORD(transitionStateHexadecimal)][ORD(transitionClassCharacter)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateHexadecimal)][ORD(transitionClassUnderscore)].Action := TransitionActionNo;
Transitions[ORD(transitionStateHexadecimal)][ORD(transitionClassUnderscore)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateHexadecimal)][ORD(transitionClassHex)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateHexadecimal)][ORD(transitionClassHex)].NextState := transitionStateHexadecimal;
Transitions[ORD(transitionStateHexadecimal)][ORD(transitionClassZero)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateHexadecimal)][ORD(transitionClassZero)].NextState := transitionStateHexadecimal;
Transitions[ORD(transitionStateHexadecimal)][ORD(transitionClassX)].Action := TransitionActionNo;
Transitions[ORD(transitionStateHexadecimal)][ORD(transitionClassX)].NextState := transitionStateEnd;
(* Comment. *)
SetDefaultTransition(transitionStateComment, TransitionActionAccumulate, transitionStateComment);
Transitions[ORD(transitionStateComment)][ORD(transitionClassAsterisk)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateComment)][ORD(transitionClassAsterisk)].NextState := transitionStateClosingComment;
Transitions[ORD(transitionStateComment)][ORD(transitionClassEof)].Action := TransitionActionNo;
Transitions[ORD(transitionStateComment)][ORD(transitionClassEof)].NextState := transitionStateEnd;
(* Closing comment. *)
SetDefaultTransition(transitionStateClosingComment, TransitionActionAccumulate, transitionStateComment);
Transitions[ORD(transitionStateClosingComment)][ORD(transitionClassInvalid)].Action := TransitionActionNo;
Transitions[ORD(transitionStateClosingComment)][ORD(transitionClassInvalid)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateClosingComment)][ORD(transitionClassRightParen)].Action := TransitionActionDelimited;
Transitions[ORD(transitionStateClosingComment)][ORD(transitionClassRightParen)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateClosingComment)][ORD(transitionClassAsterisk)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateClosingComment)][ORD(transitionClassAsterisk)].NextState := transitionStateClosingComment;
Transitions[ORD(transitionStateClosingComment)][ORD(transitionClassEof)].Action := TransitionActionNo;
Transitions[ORD(transitionStateClosingComment)][ORD(transitionClassEof)].NextState := transitionStateEnd;
(* String. *)
SetDefaultTransition(transitionStateString, TransitionActionAccumulate, transitionStateString);
Transitions[ORD(transitionStateString)][ORD(transitionClassInvalid)].Action := TransitionActionNo;
Transitions[ORD(transitionStateString)][ORD(transitionClassInvalid)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateString)][ORD(transitionClassEof)].Action := TransitionActionNo;
Transitions[ORD(transitionStateString)][ORD(transitionClassEof)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateString)][ORD(transitionClassQuote)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateString)][ORD(transitionClassQuote)].NextState := transitionStateEnd;
(* Leading zero. *)
SetDefaultTransition(transitionStateLeadingZero, TransitionActionInteger, transitionStateEnd);
Transitions[ORD(transitionStateLeadingZero)][ORD(transitionClassDigit)].Action := TransitionActionNo;
Transitions[ORD(transitionStateLeadingZero)][ORD(transitionClassDigit)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateLeadingZero)][ORD(transitionClassCharacter)].Action := TransitionActionNo;
Transitions[ORD(transitionStateLeadingZero)][ORD(transitionClassCharacter)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateLeadingZero)][ORD(transitionClassUnderscore)].Action := TransitionActionNo;
Transitions[ORD(transitionStateLeadingZero)][ORD(transitionClassUnderscore)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateLeadingZero)][ORD(transitionClassHex)].Action := TransitionActionNo;
Transitions[ORD(transitionStateLeadingZero)][ORD(transitionClassHex)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateLeadingZero)][ORD(transitionClassZero)].Action := TransitionActionNo;
Transitions[ORD(transitionStateLeadingZero)][ORD(transitionClassZero)].NextState := transitionStateEnd;
Transitions[ORD(transitionStateLeadingZero)][ORD(transitionClassX)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateLeadingZero)][ORD(transitionClassX)].NextState := transitionStateHexadecimalPrefix;
(* Leading zero. *)
SetDefaultTransition(transitionStateHexadecimalPrefix, TransitionActionNo, transitionStateEnd);
Transitions[ORD(transitionStateHexadecimalPrefix)][ORD(transitionClassDigit)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateHexadecimalPrefix)][ORD(transitionClassDigit)].NextState := transitionStateHexadecimal;
Transitions[ORD(transitionStateHexadecimalPrefix)][ORD(transitionClassHex)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateHexadecimalPrefix)][ORD(transitionClassHex)].NextState := transitionStateHexadecimal;
Transitions[ORD(transitionStateHexadecimalPrefix)][ORD(transitionClassZero)].Action := TransitionActionAccumulate;
Transitions[ORD(transitionStateHexadecimalPrefix)][ORD(transitionClassZero)].NextState := transitionStateHexadecimal
END InitializeTransitions;
BEGIN
InitializeClassification();
InitializeTransitions();
WriteString('Elna');
WriteLn()
END Compiler.

View File

@@ -1,9 +0,0 @@
{
"dependencies": {
"tanya": "~>0.18.0"
},
"name": "elna",
"targetType": "executable",
"targetPath": "build/bin",
"mainSourceFile": "source/main.d"
}

View File

@@ -1,154 +0,0 @@
/**
* Argument parsing.
*/
module elna.arguments;
import std.algorithm;
import std.range;
import std.sumtype;
struct ArgumentError
{
enum Type
{
expectedOutputFile,
noInput,
superfluousArguments,
}
private Type type_;
private string argument_;
@property Type type() const @nogc nothrow pure @safe
{
return this.type_;
}
@property string argument() const @nogc nothrow pure @safe
{
return this.argument_;
}
void toString(OR)(OR range)
if (isOutputRage!OR)
{
final switch (Type)
{
case Type.expectedOutputFile:
put(range, "Expected an output filename after -o");
break;
case Type.noInput:
put(range, "No input files specified");
break;
}
}
}
/**
* Supported compiler arguments.
*/
struct Arguments
{
private bool assembler_;
private string output_;
private string inFile_;
@property string inFile() @nogc nothrow pure @safe
{
return this.inFile_;
}
/**
* Returns: Whether to generate assembly instead of an object file.
*/
@property bool assembler() const @nogc nothrow pure @safe
{
return this.assembler_;
}
/**
* Returns: Output file.
*/
@property string output() const @nogc nothrow pure @safe
{
return this.output_;
}
/**
* Parse command line arguments.
*
* The first argument is expected to be the program name (and it is
* ignored).
*
* Params:
* arguments = Command line arguments.
*
* Returns: Parsed arguments or an error.
*/
static SumType!(ArgumentError, Arguments) parse(string[] arguments)
@nogc nothrow pure @safe
{
if (!arguments.empty)
{
arguments.popFront;
}
alias ReturnType = typeof(return);
return parseArguments(arguments).match!(
(Arguments parsed) {
if (parsed.inFile is null)
{
return ReturnType(ArgumentError(ArgumentError.Type.noInput));
}
else if (!arguments.empty)
{
return ReturnType(ArgumentError(
ArgumentError.Type.superfluousArguments,
arguments.front
));
}
return ReturnType(parsed);
},
(ArgumentError argumentError) => ReturnType(argumentError)
);
}
private static SumType!(ArgumentError, Arguments) parseArguments(ref string[] arguments)
@nogc nothrow pure @safe
{
Arguments parsed;
while (!arguments.empty)
{
if (arguments.front == "-s")
{
parsed.assembler_ = true;
}
else if (arguments.front == "-o")
{
if (arguments.empty)
{
return typeof(return)(ArgumentError(
ArgumentError.Type.expectedOutputFile,
arguments.front
));
}
arguments.popFront;
parsed.output_ = arguments.front;
}
else if (arguments.front == "--")
{
arguments.popFront;
parsed.inFile_ = arguments.front;
arguments.popFront;
break;
}
else if (!arguments.front.startsWith("-"))
{
parsed.inFile_ = arguments.front;
}
arguments.popFront;
}
return typeof(return)(parsed);
}
}

View File

@@ -1,100 +0,0 @@
module elna.backend;
import core.stdc.stdio;
import elna.elf;
import elna.ir;
import elna.extended;
import elna.riscv;
import elna.lexer;
import elna.parser;
import elna.result;
import std.algorithm;
import std.sumtype;
import std.typecons;
import tanya.os.error;
import tanya.container.array;
import tanya.container.string;
import tanya.memory.allocator;
private Nullable!String readSource(string source) @nogc
{
enum size_t bufferSize = 255;
auto sourceFilename = String(source);
return readFile(sourceFilename).match!(
(ErrorCode errorCode) {
perror(sourceFilename.toStringz);
return Nullable!String();
},
(Array!ubyte contents) => nullable(String(cast(char[]) contents.get))
);
}
int generate(string inFile, ref String outputFilename) @nogc
{
auto sourceText = readSource(inFile);
if (sourceText.isNull)
{
return 3;
}
auto tokens = lex(sourceText.get.get);
if (!tokens.valid)
{
auto compileError = tokens.error.get;
printf("%lu:%lu: %s\n", compileError.line, compileError.column, compileError.message.ptr);
return 1;
}
auto ast = parse(tokens.result);
if (!ast.valid)
{
auto compileError = ast.error.get;
printf("%lu:%lu: %s\n", compileError.line, compileError.column, compileError.message.ptr);
return 2;
}
auto transformVisitor = defaultAllocator.make!TransformVisitor();
auto ir = transformVisitor.visit(ast.result);
defaultAllocator.dispose(transformVisitor);
auto handle = File.open(outputFilename.toStringz, BitFlags!(File.Mode)(File.Mode.truncate));
if (!handle.valid)
{
return 1;
}
auto program = writeNext(ir);
auto elf = Elf!ELFCLASS32(move(handle));
auto readOnlyData = Array!ubyte(cast(const(ubyte)[]) "%d\n".ptr[0 .. 4]); // With \0.
elf.addReadOnlyData(String(".CL0"), readOnlyData);
elf.addCode(program.name, program.text);
elf.addExternSymbol(String("printf"));
foreach (ref reference; program.symbols)
{
elf.Rela relocationEntry = {
r_offset: cast(elf.Addr) reference.offset
};
elf.Rela relocationSub = {
r_offset: cast(elf.Addr) reference.offset,
r_info: R_RISCV_RELAX
};
final switch (reference.target)
{
case Reference.Target.text:
relocationEntry.r_info = R_RISCV_CALL;
break;
case Reference.Target.high20:
relocationEntry.r_info = R_RISCV_HI20;
break;
case Reference.Target.lower12i:
relocationEntry.r_info = R_RISCV_LO12_I;
break;
}
elf.relocate(reference.name, relocationEntry, relocationSub);
}
elf.finish();
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,335 +0,0 @@
/**
* File I/O that can be moved into more generic library when and if finished.
*/
module elna.extended;
import core.stdc.errno;
import core.stdc.stdio;
import std.sumtype;
import std.typecons;
import tanya.os.error;
import tanya.container.array;
import tanya.container.string;
/**
* File handle abstraction.
*/
struct File
{
/// Plattform dependent file type.
alias Handle = FILE*;
/// Uninitialized file handle value.
enum Handle invalid = null;
/**
* Relative position.
*/
enum Whence
{
/// Relative to the start of the file.
set = SEEK_SET,
/// Relative to the current cursor position.
currentt = SEEK_CUR,
/// Relative from the end of the file.
end = SEEK_END,
}
/**
* File open modes.
*/
enum Mode
{
/// Open the file for reading.
read = 1 << 0,
/// Open the file for writing. The stream is positioned at the beginning
/// of the file.
write = 1 << 1,
/// Open the file for writing and remove its contents.
truncate = 1 << 2,
/// Open the file for writing. The stream is positioned at the end of
/// the file.
append = 1 << 3,
}
private enum Status
{
invalid,
owned,
borrowed,
}
private union Storage
{
Handle handle;
ErrorCode errorCode;
}
private Storage storage;
private Status status = Status.invalid;
@disable this(scope return ref File f);
@disable this();
/**
* Closes the file.
*/
~this() @nogc nothrow
{
if (this.status == Status.owned)
{
fclose(this.storage.handle);
}
this.storage.handle = invalid;
this.status = Status.invalid;
}
/**
* Construct the object with the given system handle. The won't be claused
* in the descructor if this constructor is used.
*
* Params:
* handle = File handle to be wrapped by this structure.
*/
this(Handle handle) @nogc nothrow pure @safe
{
this.storage.handle = handle;
this.status = Status.borrowed;
}
/**
* Returns: Plattform dependent file handle.
*/
@property Handle handle() @nogc nothrow pure @trusted
{
return valid ? this.storage.handle : invalid;
}
/**
* Returns: An error code if an error has occurred.
*/
@property ErrorCode errorCode() @nogc nothrow pure @safe
{
return valid ? ErrorCode() : this.storage.errorCode;
}
/**
* Returns: Whether a valid, opened file is represented.
*/
@property bool valid() @nogc nothrow pure @safe
{
return this.status != Status.invalid;
}
/**
* Transfers the file into invalid state.
*
* Returns: The old file handle.
*/
Handle reset() @nogc nothrow pure @safe
{
if (!valid)
{
return invalid;
}
auto oldHandle = handle;
this.status = Status.invalid;
this.storage.errorCode = ErrorCode();
return oldHandle;
}
/**
* Sets stream position in the file.
*
* Params:
* offset = File offset.
* whence = File position to add the offset to.
*
* Returns: Error code if any.
*/
ErrorCode seek(size_t offset, Whence whence) @nogc nothrow
{
if (!valid)
{
return ErrorCode(ErrorCode.ErrorNo.badDescriptor);
}
if (fseek(this.storage.handle, offset, whence))
{
return ErrorCode(cast(ErrorCode.ErrorNo) errno);
}
return ErrorCode();
}
/**
* Returns: Current offset or an error.
*/
SumType!(ErrorCode, size_t) tell() @nogc nothrow
{
if (!valid)
{
return typeof(return)(ErrorCode(ErrorCode.ErrorNo.badDescriptor));
}
auto result = ftell(this.storage.handle);
if (result < 0)
{
return typeof(return)(ErrorCode(cast(ErrorCode.ErrorNo) errno));
}
return typeof(return)(cast(size_t) result);
}
/**
* Params:
* buffer = Destination buffer.
*
* Returns: Bytes read. $(D_PSYMBOL ErrorCode.ErrorNo.success) means that
* while reading the file an unknown error has occurred.
*/
SumType!(ErrorCode, size_t) read(ubyte[] buffer) @nogc nothrow
{
if (!valid)
{
return typeof(return)(ErrorCode(ErrorCode.ErrorNo.badDescriptor));
}
const bytesRead = fread(buffer.ptr, 1, buffer.length, this.storage.handle);
if (bytesRead == buffer.length || eof())
{
return typeof(return)(bytesRead);
}
return typeof(return)(ErrorCode());
}
/**
* Params:
* buffer = Source buffer.
*
* Returns: Bytes written. $(D_PSYMBOL ErrorCode.ErrorNo.success) means that
* while reading the file an unknown error has occurred.
*/
SumType!(ErrorCode, size_t) write(const(ubyte)[] buffer) @nogc nothrow
{
if (!valid)
{
return typeof(return)(ErrorCode(ErrorCode.ErrorNo.badDescriptor));
}
const bytesWritten = fwrite(buffer.ptr, 1, buffer.length, this.storage.handle);
if (bytesWritten == buffer.length)
{
return typeof(return)(buffer.length);
}
return typeof(return)(ErrorCode());
}
/**
* Returns: EOF status of the file.
*/
bool eof() @nogc nothrow
{
return valid && feof(this.storage.handle) != 0;
}
/**
* Constructs a file object that will be closed in the destructor.
*
* Params:
* filename = The file to open.
*
* Returns: Opened file or an error.
*/
static File open(const(char)* filename, BitFlags!Mode mode) @nogc nothrow
{
char[3] modeBuffer = "\0\0\0";
if (mode.truncate)
{
modeBuffer[0] = 'w';
if (mode.read)
{
modeBuffer[1] = '+';
}
}
else if (mode.append)
{
modeBuffer[0] = 'a';
if (mode.read)
{
modeBuffer[1] = '+';
}
}
else if (mode.read)
{
modeBuffer[0] = 'r';
if (mode.write)
{
modeBuffer[1] = '+';
}
}
auto newHandle = fopen(filename, modeBuffer.ptr);
auto newFile = File(newHandle);
if (newHandle is null)
{
newFile.status = Status.invalid;
newFile.storage.errorCode = ErrorCode(cast(ErrorCode.ErrorNo) errno);
}
else
{
if (mode == BitFlags!Mode(Mode.write))
{
rewind(newHandle);
}
newFile.status = Status.owned;
}
return newFile;
}
}
/**
* Reads the whole file and returns its contents.
*
* Params:
* sourceFilename = Source filename.
*
* Returns: File contents or an error.
*
* See_Also: $(D_PSYMBOL File.read)
*/
SumType!(ErrorCode, Array!ubyte) readFile(String sourceFilename) @nogc
{
enum size_t bufferSize = 255;
auto sourceFile = File.open(sourceFilename.toStringz, BitFlags!(File.Mode)(File.Mode.read));
if (!sourceFile.valid)
{
return typeof(return)(sourceFile.errorCode);
}
Array!ubyte sourceText;
size_t totalRead;
size_t bytesRead;
do
{
sourceText.length = sourceText.length + bufferSize;
const readStatus = sourceFile
.read(sourceText[totalRead .. $].get)
.match!(
(ErrorCode errorCode) => nullable(errorCode),
(size_t bytesRead_) {
bytesRead = bytesRead_;
return Nullable!ErrorCode();
}
);
if (!readStatus.isNull)
{
return typeof(return)(readStatus.get);
}
totalRead += bytesRead;
}
while (bytesRead == bufferSize);
sourceText.length = totalRead;
return typeof(return)(sourceText);
}

View File

@@ -1,272 +0,0 @@
module elna.ir;
import parser = elna.parser;
import tanya.container.array;
import tanya.container.hashtable;
import tanya.container.string;
import tanya.memory.allocator;
public import elna.parser : BinaryOperator;
/**
* Mapping between the parser and IR AST.
*/
struct ASTMapping
{
alias Node = .Node;
alias Definition = .Definition;
alias VariableDeclaration = .VariableDeclaration;
alias Statement = Array!(.Statement);
alias BangStatement = .Expression;
alias Block = .Definition;
alias Expression = .Expression;
alias Number = .Number;
alias Variable = .Variable;
alias BinaryExpression = .BinaryExpression;
}
/**
* IR visitor.
*/
interface IRVisitor
{
abstract void visit(Node) @nogc;
abstract void visit(Definition) @nogc;
abstract void visit(Expression) @nogc;
abstract void visit(Statement) @nogc;
abstract void visit(Variable) @nogc;
abstract void visit(VariableDeclaration) @nogc;
abstract void visit(Number) @nogc;
abstract void visit(BinaryExpression) @nogc;
}
/**
* AST node.
*/
abstract class Node
{
abstract void accept(IRVisitor) @nogc;
}
/**
* Definition.
*/
class Definition : Node
{
char[] identifier;
Array!Statement statements;
Array!VariableDeclaration variableDeclarations;
override void accept(IRVisitor visitor) @nogc
{
visitor.visit(this);
}
}
class Statement : Node
{
BinaryExpression expression;
override void accept(IRVisitor visitor) @nogc
{
visitor.visit(this);
}
}
abstract class Expression : Node
{
override void accept(IRVisitor visitor) @nogc
{
visitor.visit(this);
}
}
class Number : Expression
{
int value;
override void accept(IRVisitor visitor) @nogc
{
visitor.visit(this);
}
}
class Variable : Expression
{
size_t counter;
override void accept(IRVisitor visitor) @nogc
{
visitor.visit(this);
}
}
class VariableDeclaration : Node
{
String identifier;
override void accept(IRVisitor visitor) @nogc
{
visitor.visit(this);
}
}
class BinaryExpression : Node
{
Expression lhs, rhs;
BinaryOperator operator;
this(Expression lhs, Expression rhs, BinaryOperator operator)
@nogc
{
this.lhs = lhs;
this.rhs = rhs;
this.operator = operator;
}
override void accept(IRVisitor visitor) @nogc
{
visitor.visit(this);
}
}
final class TransformVisitor : parser.ParserVisitor!ASTMapping
{
private HashTable!(String, int) constants;
ASTMapping.Node visit(parser.Node node) @nogc
{
assert(false, "Not implemented");
}
ASTMapping.Definition visit(parser.Definition definition) @nogc
{
assert(false, "Not implemented");
}
ASTMapping.VariableDeclaration visit(parser.VariableDeclaration declaration) @nogc
{
assert(false, "Not implemented");
}
ASTMapping.BangStatement visit(parser.BangStatement statement) @nogc
{
assert(false, "Not implemented");
}
ASTMapping.Block visit(parser.Block block) @nogc
{
auto target = defaultAllocator.make!Definition;
this.constants = transformConstants(block.definitions);
target.statements = block.statement.accept(this);
target.variableDeclarations = transformVariableDeclarations(block.variableDeclarations);
return target;
}
ASTMapping.Expression visit(parser.Expression expression) @nogc
{
assert(false, "Not implemented");
}
ASTMapping.Number visit(parser.Number number) @nogc
{
assert(false, "Not implemented");
}
ASTMapping.Variable visit(parser.Variable variable) @nogc
{
assert(false, "Not implemented");
}
ASTMapping.BinaryExpression visit(parser.BinaryExpression) @nogc
{
assert(false, "Not implemented");
}
private Number transformNumber(parser.Number number) @nogc
{
return defaultAllocator.make!Number(number.value);
}
private Variable binaryExpression(parser.BinaryExpression binaryExpression,
ref Array!Statement statements) @nogc
{
auto target = defaultAllocator.make!BinaryExpression(
expression(binaryExpression.lhs, statements),
expression(binaryExpression.rhs, statements),
binaryExpression.operator
);
auto newStatement = defaultAllocator.make!Statement;
newStatement.expression = target;
statements.insertBack(newStatement);
auto newVariable = defaultAllocator.make!Variable;
newVariable.counter = statements.length;
return newVariable;
}
private Expression expression(parser.Expression expression,
ref Array!Statement statements) @nogc
{
if ((cast(parser.Number) expression) !is null)
{
auto numberExpression = defaultAllocator.make!Number;
numberExpression.value = (cast(parser.Number) expression).value;
return numberExpression;
}
if ((cast(parser.Variable) expression) !is null)
{
auto numberExpression = defaultAllocator.make!Number;
numberExpression.value = this.constants[(cast(parser.Variable) expression).identifier];
return numberExpression;
}
else if ((cast(parser.BinaryExpression) expression) !is null)
{
return binaryExpression(cast(parser.BinaryExpression) expression, statements);
}
return null;
}
override Array!Statement visit(parser.Statement statement) @nogc
{
typeof(return) statements;
if ((cast(parser.BangStatement) statement) !is null)
{
expression((cast(parser.BangStatement) statement).expression, statements);
}
return statements;
}
private HashTable!(String, int) transformConstants(ref Array!(parser.Definition) definitions) @nogc
{
typeof(return) constants;
foreach (definition; definitions[])
{
constants[definition.identifier] = definition.number.value;
}
return constants;
}
Array!VariableDeclaration transformVariableDeclarations(ref Array!(parser.VariableDeclaration) variableDeclarations)
@nogc
{
typeof(return) variables;
foreach (ref variableDeclaration; variableDeclarations)
{
auto newDeclaration = defaultAllocator.make!VariableDeclaration;
newDeclaration.identifier = variableDeclaration.identifier;
variables.insertBack(newDeclaration);
}
return variables;
}
}

View File

@@ -1,254 +0,0 @@
module elna.lexer;
import core.stdc.stdlib;
import core.stdc.ctype;
import core.stdc.string;
import elna.result;
import std.range;
import tanya.container.array;
import tanya.container.string;
struct Token
{
enum Type
{
number,
operator,
let,
identifier,
equals,
var,
semicolon,
leftParen,
rightParen,
bang,
dot,
comma,
}
union Value
{
int number;
String identifier;
}
private Type type;
private Value value_;
private Position position_;
@disable this();
this(Type type, Position position) @nogc nothrow pure @safe
{
this.type = type;
this.position_ = position;
}
this(Type type, int value, Position position) @nogc nothrow pure @trusted
in (type == Type.number)
{
this(type, position);
this.value_.number = value;
}
this()(Type type, auto ref String value, Position position)
@nogc nothrow pure @trusted
in (type == Type.identifier || type == Type.operator)
{
this(type, position);
this.value_.identifier = value;
}
/**
* Params:
* type = Expected type.
*
* Returns: Whether this token is of the expected type.
*/
bool ofType(Type type) const @nogc nothrow pure @safe
{
return this.type == type;
}
@property auto value(Type type)() @nogc nothrow pure @trusted
in (ofType(type))
{
static if (type == Type.number)
{
return this.value_.number;
}
else static if (type == Type.identifier || type == Type.operator)
{
return this.value_.identifier;
}
else
{
static assert(false, "This type doesn't have a value");
}
}
/**
* Returns: The token position in the source text.
*/
@property const(Position) position() const @nogc nothrow pure @safe
{
return this.position_;
}
}
/**
* Range over the source text that keeps track of the current position.
*/
struct Source
{
char[] buffer;
Position position;
this(char[] buffer) @nogc nothrow pure @safe
{
this.buffer = buffer;
}
@disable this();
bool empty() @nogc nothrow pure @safe
{
return this.length == 0;
}
char front() @nogc nothrow pure @safe
in (!empty)
{
return this.buffer[0];
}
void popFront() @nogc nothrow pure @safe
in (!empty)
{
this.buffer = buffer[1 .. $];
++this.position.column;
}
void breakLine() @nogc nothrow pure @safe
in (!empty)
{
this.buffer = buffer[1 .. $];
++this.position.line;
this.position.column = 1;
}
@property size_t length() const @nogc nothrow pure @safe
{
return this.buffer.length;
}
char opIndex(size_t index) @nogc nothrow pure @safe
in (index < length)
{
return this.buffer[index];
}
char[] opSlice(size_t i, size_t j) @nogc nothrow pure @safe
in
{
assert(i <= j);
assert(j <= length);
}
do
{
return this.buffer[i .. j];
}
}
Result!(Array!Token) lex(char[] buffer) @nogc
{
Array!Token tokens;
auto source = Source(buffer);
while (!source.empty)
{
if (source.front == ' ')
{
source.popFront;
}
else if (source.front >= '0' && source.front <= '9') // Multi-digit.
{
tokens.insertBack(Token(Token.Type.number, source.front - '0', source.position));
source.popFront;
}
else if (source.front == '=')
{
tokens.insertBack(Token(Token.Type.equals, source.position));
source.popFront;
}
else if (source.front == '(')
{
tokens.insertBack(Token(Token.Type.leftParen, source.position));
source.popFront;
}
else if (source.front == ')')
{
tokens.insertBack(Token(Token.Type.rightParen, source.position));
source.popFront;
}
else if (source.front == ';')
{
tokens.insertBack(Token(Token.Type.semicolon, source.position));
source.popFront;
}
else if (source.front == ',')
{
tokens.insertBack(Token(Token.Type.comma, source.position));
source.popFront;
}
else if (source.front == '!')
{
tokens.insertBack(Token(Token.Type.bang, source.position));
source.popFront;
}
else if (source.front == '.')
{
tokens.insertBack(Token(Token.Type.dot, source.position));
source.popFront;
}
else if (isalpha(source.front))
{
size_t i = 1;
while (i < source.length && isalpha(source[i]))
{
++i;
}
if (source[0 .. i] == "const")
{
tokens.insertBack(Token(Token.Type.let, source.position));
}
else if (source[0 .. i] == "var")
{
tokens.insertBack(Token(Token.Type.var, source.position));
}
else
{
auto identifier = String(source[0 .. i]);
tokens.insertBack(Token(Token.Type.identifier, identifier, source.position));
}
source.popFrontN(i);
}
else if (source.front == '+' || source.front == '-')
{
String operator;
operator.insertBack(source.front);
tokens.insertBack(Token(Token.Type.operator, operator, source.position));
source.popFront;
}
else if (source.front == '\n')
{
source.breakLine;
}
else
{
return typeof(return)("Unexptected next character", source.position);
}
}
return typeof(return)(tokens);
}

View File

@@ -1,372 +0,0 @@
module elna.parser;
import elna.lexer;
import elna.result;
import tanya.container.array;
import tanya.container.string;
import tanya.memory.allocator;
/**
* Parser visitor.
*/
interface ParserVisitor(Mapping)
{
Mapping.Node visit(Node) @nogc;
Mapping.Definition visit(Definition) @nogc;
Mapping.VariableDeclaration visit(VariableDeclaration) @nogc;
Mapping.Statement visit(Statement) @nogc;
Mapping.BangStatement visit(BangStatement) @nogc;
Mapping.Block visit(Block) @nogc;
Mapping.Expression visit(Expression) @nogc;
Mapping.Number visit(Number) @nogc;
Mapping.Variable visit(Variable) @nogc;
Mapping.BinaryExpression visit(BinaryExpression) @nogc;
}
/**
* AST node.
*/
abstract class Node
{
Mapping.Node accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
}
/**
* Constant definition.
*/
class Definition : Node
{
Number number;
String identifier;
Mapping.Definition accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
}
/**
* Variable declaration.
*/
class VariableDeclaration : Node
{
String identifier;
Mapping.VariableDeclaration accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
}
abstract class Statement : Node
{
Mapping.Statement accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
}
class BangStatement : Statement
{
Expression expression;
Mapping.BangStatement accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
}
class Block : Node
{
Array!Definition definitions;
Array!VariableDeclaration variableDeclarations;
Statement statement;
Mapping.Block accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
}
abstract class Expression : Node
{
Mapping.Expression accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
}
class Number : Expression
{
int value;
Mapping.Number accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
}
class Variable : Expression
{
String identifier;
Mapping.Variable accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
}
enum BinaryOperator
{
sum,
subtraction
}
class BinaryExpression : Expression
{
Expression lhs, rhs;
BinaryOperator operator;
this(Expression lhs, Expression rhs, String operator) @nogc
{
this.lhs = lhs;
this.rhs = rhs;
if (operator == "+")
{
this.operator = BinaryOperator.sum;
}
else if (operator == "-")
{
this.operator = BinaryOperator.subtraction;
}
else
{
assert(false, "Invalid binary operator");
}
}
Mapping.BinaryExpression accept(Mapping)(ParserVisitor!Mapping visitor) @nogc
{
return visitor.visit(this);
}
}
private Result!Expression parseFactor(ref Array!Token.Range tokens) @nogc
in (!tokens.empty, "Expected factor, got end of stream")
{
if (tokens.front.ofType(Token.Type.identifier))
{
auto variable = defaultAllocator.make!Variable;
variable.identifier = tokens.front.value!(Token.Type.identifier);
tokens.popFront;
return Result!Expression(variable);
}
else if (tokens.front.ofType(Token.Type.number))
{
auto number = defaultAllocator.make!Number;
number.value = tokens.front.value!(Token.Type.number);
tokens.popFront;
return Result!Expression(number);
}
else if (tokens.front.ofType(Token.Type.leftParen))
{
tokens.popFront;
auto expression = parseExpression(tokens);
tokens.popFront;
return expression;
}
return Result!Expression("Expected a factor", tokens.front.position);
}
private Result!Expression parseTerm(ref Array!(Token).Range tokens) @nogc
{
return parseFactor(tokens);
}
private Result!Expression parseExpression(ref Array!(Token).Range tokens) @nogc
in (!tokens.empty, "Expected expression, got end of stream")
{
auto term = parseTerm(tokens);
if (!term.valid || tokens.empty || !tokens.front.ofType(Token.Type.operator))
{
return term;
}
auto operator = tokens.front.value!(Token.Type.operator);
tokens.popFront;
auto expression = parseExpression(tokens);
if (expression.valid)
{
auto binaryExpression = defaultAllocator
.make!BinaryExpression(term.result, expression.result, operator);
return Result!Expression(binaryExpression);
}
else
{
return Result!Expression("Expected right-hand side to be an expression", tokens.front.position);
}
}
private Result!Definition parseDefinition(ref Array!Token.Range tokens) @nogc
in (!tokens.empty, "Expected definition, got end of stream")
{
auto definition = defaultAllocator.make!Definition;
definition.identifier = tokens.front.value!(Token.Type.identifier); // Copy.
tokens.popFront();
tokens.popFront(); // Skip the equals sign.
if (tokens.front.ofType(Token.Type.number))
{
auto number = defaultAllocator.make!Number;
number.value = tokens.front.value!(Token.Type.number);
definition.number = number;
tokens.popFront;
return Result!Definition(definition);
}
return Result!Definition("Expected a number", tokens.front.position);
}
private Result!Statement parseStatement(ref Array!Token.Range tokens) @nogc
in (!tokens.empty, "Expected block, got end of stream")
{
if (tokens.front.ofType(Token.Type.bang))
{
tokens.popFront;
auto statement = defaultAllocator.make!BangStatement;
auto expression = parseExpression(tokens);
if (expression.valid)
{
statement.expression = expression.result;
}
else
{
return Result!Statement(expression.error.get);
}
return Result!Statement(statement);
}
return Result!Statement("Expected ! statement", tokens.front.position);
}
private Result!(Array!Definition) parseDefinitions(ref Array!Token.Range tokens) @nogc
in (!tokens.empty, "Expected definition, got end of stream")
{
tokens.popFront; // Skip const.
Array!Definition definitions;
while (!tokens.empty)
{
auto definition = parseDefinition(tokens);
if (!definition.valid)
{
return typeof(return)(definition.error.get);
}
definitions.insertBack(definition.result);
if (tokens.front.ofType(Token.Type.semicolon))
{
break;
}
if (tokens.front.ofType(Token.Type.comma))
{
tokens.popFront;
}
}
return typeof(return)(definitions);
}
private Result!(Array!VariableDeclaration) parseVariableDeclarations(ref Array!Token.Range tokens) @nogc
in (!tokens.empty, "Expected variable declarations, got end of stream")
{
tokens.popFront; // Skip var.
Array!VariableDeclaration variableDeclarations;
while (!tokens.empty)
{
auto currentToken = tokens.front;
if (currentToken.ofType(Token.Type.identifier))
{
auto variableDeclaration = defaultAllocator.make!VariableDeclaration;
variableDeclaration.identifier = currentToken.value!(Token.Type.identifier);
variableDeclarations.insertBack(variableDeclaration);
tokens.popFront;
}
else
{
return typeof(return)("Expected variable name", tokens.front.position);
}
if (tokens.empty)
{
return typeof(return)("Expected \";\" or \",\" name", currentToken.position);
}
if (tokens.front.ofType(Token.Type.semicolon))
{
break;
}
if (tokens.front.ofType(Token.Type.comma))
{
tokens.popFront;
}
}
return typeof(return)(variableDeclarations);
}
private Result!Block parseBlock(ref Array!Token.Range tokens) @nogc
in (!tokens.empty, "Expected block, got end of stream")
{
auto block = defaultAllocator.make!Block;
if (tokens.front.ofType(Token.Type.let))
{
auto constDefinitions = parseDefinitions(tokens);
if (constDefinitions.valid)
{
block.definitions = constDefinitions.result;
}
else
{
return Result!Block(constDefinitions.error.get);
}
tokens.popFront;
}
if (tokens.front.ofType(Token.Type.var))
{
auto variableDeclarations = parseVariableDeclarations(tokens);
if (variableDeclarations.valid)
{
block.variableDeclarations = variableDeclarations.result;
}
else
{
return Result!Block(variableDeclarations.error.get);
}
tokens.popFront;
}
auto statement = parseStatement(tokens);
if (statement.valid)
{
block.statement = statement.result;
}
else
{
return Result!Block(statement.error.get);
}
return Result!Block(block);
}
Result!Block parse(ref Array!Token tokenStream) @nogc
{
auto tokens = tokenStream[];
return parseBlock(tokens);
}

View File

@@ -1,107 +0,0 @@
module elna.result;
import std.typecons;
import tanya.container.array;
import tanya.container.string;
/**
* Position in the source text.
*/
struct Position
{
/// Line.
size_t line = 1;
/// Column.
size_t column = 1;
}
struct CompileError
{
private string message_;
private Position position_;
@disable this();
/**
* Params:
* message = Error text.
* position = Error position in the source text.
*/
this(string message, Position position) @nogc nothrow pure @safe
{
this.message_ = message;
this.position_ = position;
}
/// Error text.
@property string message() const @nogc nothrow pure @safe
{
return this.message_;
}
/// Error line in the source text.
@property size_t line() const @nogc nothrow pure @safe
{
return this.position_.line;
}
/// Error column in the source text.
@property size_t column() const @nogc nothrow pure @safe
{
return this.position_.column;
}
}
struct Result(T)
{
Nullable!CompileError error;
T result;
this(T result)
{
this.result = result;
this.error = typeof(this.error).init;
}
this(string message, Position position)
{
this.result = T.init;
this.error = CompileError(message, position);
}
this(CompileError compileError)
{
this.result = null;
this.error = compileError;
}
@disable this();
@property bool valid() const
{
return error.isNull;
}
}
struct Reference
{
enum Target
{
text,
high20,
lower12i
}
String name;
size_t offset;
Target target;
}
struct Symbol
{
String name;
Array!ubyte text;
Array!Reference symbols;
}

View File

@@ -1,352 +0,0 @@
module elna.riscv;
import elna.extended;
import elna.ir;
import elna.result;
import std.algorithm;
import std.typecons;
import tanya.container.array;
import tanya.container.string;
import tanya.memory.allocator;
enum XRegister : ubyte
{
zero = 0,
ra = 1,
sp = 2,
gp = 3,
tp = 4,
t0 = 5,
t1 = 6,
t2 = 7,
s0 = 8,
s1 = 9,
a0 = 10,
a1 = 11,
a2 = 12,
a3 = 13,
a4 = 14,
a5 = 15,
a6 = 16,
a7 = 17,
s2 = 18,
s3 = 19,
s4 = 20,
s5 = 21,
s6 = 22,
s7 = 23,
s8 = 24,
s9 = 25,
s10 = 26,
s11 = 27,
t3 = 28,
t4 = 29,
t5 = 30,
t6 = 31,
}
enum Funct3 : ubyte
{
addi = 0b000,
slti = 0b001,
sltiu = 0b011,
andi = 0b111,
ori = 0b110,
xori = 0b100,
slli = 0b000,
srli = 0b101,
srai = 0b101,
add = 0b000,
slt = 0b010,
sltu = 0b011,
and = 0b111,
or = 0b110,
xor = 0b100,
sll = 0b001,
srl = 0b101,
sub = 0b000,
sra = 0b101,
beq = 0b000,
bne = 0b001,
blt = 0b100,
bltu = 0b110,
bge = 0b101,
bgeu = 0b111,
fence = 0b000,
fenceI = 0b001,
csrrw = 0b001,
csrrs = 0b010,
csrrc = 0b011,
csrrwi = 0b101,
csrrsi = 0b110,
csrrci = 0b111,
priv = 0b000,
sb = 0b000,
sh = 0b001,
sw = 0b010,
lb = 0b000,
lh = 0b001,
lw = 0b010,
lbu = 0b100,
lhu = 0b101,
jalr = 0b000,
}
enum Funct12 : ubyte
{
ecall = 0b000000000000,
ebreak = 0b000000000001,
}
enum Funct7 : ubyte
{
none = 0,
sub = 0b0100000
}
enum BaseOpcode : ubyte
{
opImm = 0b0010011,
lui = 0b0110111,
auipc = 0b0010111,
op = 0b0110011,
jal = 0b1101111,
jalr = 0b1100111,
branch = 0b1100011,
load = 0b0000011,
store = 0b0100011,
miscMem = 0b0001111,
system = 0b1110011,
}
struct Instruction
{
private uint instruction;
this(BaseOpcode opcode) @nogc
{
this.instruction = opcode;
}
@disable this();
ref Instruction i(XRegister rd, Funct3 funct3, XRegister rs1, uint immediate)
return scope @nogc
{
this.instruction |= (rd << 7)
| (funct3 << 12)
| (rs1 << 15)
| (immediate << 20);
return this;
}
ref Instruction s(uint imm1, Funct3 funct3, XRegister rs1, XRegister rs2, uint imm2 = 0)
return scope @nogc
{
this.instruction |= (imm1 << 7)
| (funct3 << 12)
| (rs1 << 15)
| (rs2 << 20)
| (imm2 << 25);
return this;
}
ref Instruction r(XRegister rd, Funct3 funct3, XRegister rs1, XRegister rs2, Funct7 funct7 = Funct7.none)
return scope @nogc
{
this.instruction |= (rd << 7)
| (funct3 << 12)
| (rs1 << 15)
| (rs2 << 20)
| (funct7 << 25);
return this;
}
ref Instruction u(XRegister rd, uint imm)
return scope @nogc
{
this.instruction |= (rd << 7) | (imm << 12);
return this;
}
ubyte[] encode() return scope @nogc
{
return (cast(ubyte*) (&this.instruction))[0 .. uint.sizeof];
}
}
class RiscVVisitor : IRVisitor
{
Array!Instruction instructions;
bool registerInUse;
uint variableCounter = 1;
Array!Reference references;
override void visit(Node) @nogc
{
}
override void visit(Definition definition) @nogc
{
// Prologue.
this.instructions.insertBack(
Instruction(BaseOpcode.opImm)
.i(XRegister.sp, Funct3.addi, XRegister.sp, cast(uint) -32)
);
this.instructions.insertBack(
Instruction(BaseOpcode.store)
.s(28, Funct3.sw, XRegister.sp, XRegister.s0)
);
this.instructions.insertBack(
Instruction(BaseOpcode.store)
.s(24, Funct3.sw, XRegister.sp, XRegister.ra)
);
this.instructions.insertBack(
Instruction(BaseOpcode.opImm)
.i(XRegister.s0, Funct3.addi, XRegister.sp, 32)
);
foreach (statement; definition.statements[])
{
statement.accept(this);
}
foreach (variableDeclaration; definition.variableDeclarations[])
{
variableDeclaration.accept(this);
}
// Print the result.
this.instructions.insertBack(
Instruction(BaseOpcode.opImm)
.i(XRegister.a1, Funct3.addi, XRegister.a0, 0)
);
this.references.insertBack(Reference(String(".CL0"), instructions.length * 4, Reference.Target.high20));
this.instructions.insertBack(
Instruction(BaseOpcode.lui).u(XRegister.a5, 0)
);
this.references.insertBack(Reference(String(".CL0"), instructions.length * 4, Reference.Target.lower12i));
this.instructions.insertBack(
Instruction(BaseOpcode.opImm).i(XRegister.a0, Funct3.addi, XRegister.a5, 0)
);
this.references.insertBack(Reference(String("printf"), instructions.length * 4, Reference.Target.text));
this.instructions.insertBack(
Instruction(BaseOpcode.auipc).u(XRegister.ra, 0)
);
this.instructions.insertBack(
Instruction(BaseOpcode.jalr)
.i(XRegister.ra, Funct3.jalr, XRegister.ra, 0)
);
// Set the return value (0).
this.instructions.insertBack(
Instruction(BaseOpcode.op)
.r(XRegister.a0, Funct3.and, XRegister.zero, XRegister.zero)
);
// Epilogue.
this.instructions.insertBack(
Instruction(BaseOpcode.load)
.i(XRegister.s0, Funct3.lw, XRegister.sp, 28)
);
this.instructions.insertBack(
Instruction(BaseOpcode.load)
.i(XRegister.ra, Funct3.lw, XRegister.sp, 24)
);
this.instructions.insertBack(
Instruction(BaseOpcode.opImm)
.i(XRegister.sp, Funct3.addi, XRegister.sp, 32)
);
this.instructions.insertBack(
Instruction(BaseOpcode.jalr)
.i(XRegister.zero, Funct3.jalr, XRegister.ra, 0)
);
}
override void visit(Expression) @nogc
{
}
override void visit(Statement statement) @nogc
{
statement.expression.accept(this);
}
override void visit(Variable variable) @nogc
{
const freeRegister = this.registerInUse ? XRegister.a0 : XRegister.t0;
// movl -x(%rbp), %eax; where x is a number.
this.instructions.insertBack(
Instruction(BaseOpcode.load)
.i(freeRegister, Funct3.lw, XRegister.sp,
cast(byte) (variable.counter * 4))
);
}
override void visit(VariableDeclaration) @nogc
{
}
override void visit(Number number) @nogc
{
const freeRegister = this.registerInUse ? XRegister.a0 : XRegister.t0;
this.instructions.insertBack(
Instruction(BaseOpcode.opImm) // movl $x, %eax; where $x is a number.
.i(freeRegister, Funct3.addi, XRegister.zero, number.value)
);
}
override void visit(BinaryExpression expression) @nogc
{
this.registerInUse = true;
expression.lhs.accept(this);
this.registerInUse = false;
expression.rhs.accept(this);
// Calculate the result and assign it to a variable on the stack.
final switch (expression.operator)
{
case BinaryOperator.sum:
this.instructions.insertBack(
Instruction(BaseOpcode.op)
.r(XRegister.a0, Funct3.add, XRegister.a0, XRegister.t0)
);
break;
case BinaryOperator.subtraction:
this.instructions.insertBack(
Instruction(BaseOpcode.op)
.r(XRegister.a0, Funct3.sub, XRegister.a0, XRegister.t0, Funct7.sub)
);
break;
}
this.instructions.insertBack( // movl %eax, -x(%rbp); where x is a number.
Instruction(BaseOpcode.store)
.s(cast(uint) (this.variableCounter * 4), Funct3.sw, XRegister.sp, XRegister.a0)
);
++this.variableCounter;
}
}
Symbol writeNext(Definition ast) @nogc
{
Array!Instruction instructions;
Array!Reference references;
auto visitor = defaultAllocator.make!RiscVVisitor;
scope (exit)
{
defaultAllocator.dispose(visitor);
}
visitor.visit(ast);
auto program = Symbol(String("main"));
program.symbols = move(visitor.references);
foreach (ref instruction; visitor.instructions)
{
program.text.insertBack(instruction.encode);
}
return program;
}

View File

@@ -1,33 +0,0 @@
import elna.backend;
import elna.ir;
import elna.arguments;
import std.path;
import std.sumtype;
import tanya.container.string;
import tanya.memory.allocator;
import tanya.memory.mmappool;
int main(string[] args)
{
defaultAllocator = MmapPool.instance;
return Arguments.parse(args).match!(
(ArgumentError argumentError) => 4,
(Arguments arguments) {
String outputFilename;
if (arguments.output is null)
{
outputFilename = arguments
.inFile
.baseName
.withExtension("o");
}
else
{
outputFilename = String(arguments.output);
}
return generate(arguments.inFile, outputFilename);
}
);
}

View File

@@ -1,3 +0,0 @@
const a = 1, b = 2;
! a + b
.

View File

@@ -1 +0,0 @@
3

View File

@@ -1 +0,0 @@
8

View File

@@ -1 +0,0 @@
1

View File

@@ -1 +0,0 @@
8

View File

@@ -1 +0,0 @@
8

View File

@@ -1,2 +0,0 @@
! (3 + 4) + 1
.

View File

@@ -1,2 +0,0 @@
! 5 - 4
.

View File

@@ -1,2 +0,0 @@
! 1 + 7
.

View File

@@ -1,2 +0,0 @@
! 1 + (3 + 4)
.