Compiler/code generator: Difference between revisions
Content added Content deleted
No edit summary |
|||
Line 2,704: | Line 2,704: | ||
65 halt |
65 halt |
||
</pre> |
</pre> |
||
=={{header|M2000 Interpreter}}== |
|||
<lang M2000 Interpreter> |
|||
Module CodeGenerator (s$){ |
|||
Function code$(op$) { |
|||
=format$("{0::-6} {1}", pc, op$) |
|||
pc++ |
|||
} |
|||
Function code2$(op$, n$) { |
|||
=format$("{0::-6} {1} {2}", pc, op$, n$) |
|||
pc+=5 |
|||
} |
|||
Function code3$(op$,pc, st, ed) { |
|||
=format$("{0::-6} {1} ({2}) {3}", pc, op$, ed-st-1, ed) |
|||
} |
|||
Enum tok { |
|||
gneg, gnot, gmul, gdiv, gmod, gadd, gle, gsub, glt |
|||
gle, ggt, gge, geq, gne, gand, gor, gputc, gprti, gprts, |
|||
gif, gwhile, gAssign, gSeq, gstring, gidentifier, gint, gnone |
|||
} |
|||
\\ Inventories are list with keys, or keys/data (key must be unique) |
|||
\\ there is one type more the Invetory Queue which get same keys. |
|||
\\ But here not used. |
|||
Inventory symb="Multiply":=gmul, "Divide":=gdiv, "Mod":=gmod, "Add":=gadd |
|||
Append symb, "Negate":=gneg, "Not":=gnot,"Less":=glt,"Subtract":=gsub |
|||
Append symb, "LessEqual":=gle, "Greater":=ggt, "GreaterEqual":=gge, "Sequence":=gSeq |
|||
Append symb, "Equal":=geq, "NotEqual":=gne, "And":=gand, "Or":=gor, "While":=gwhile |
|||
Append symb, "Putc":=gputc,"Prti":=gprti,"Prts":=gprts, "Assign":=gAssign, "If":=gif |
|||
Append symb, "String":=gstring, "Identifier":=gidentifier, "Integer":=gint, ";", gnone |
|||
Inventory DataSet |
|||
\\ We set string as key. key maybe an empty string, a string or a number. |
|||
\\ so we want eash string to saved one time only. |
|||
Inventory Strings |
|||
Const nl$=chr$(13)+chr$(10), Ansi=3 |
|||
Def z$, lim, line$, newvar_ok, i=0 |
|||
Document message$=nl$ |
|||
Global pc \\ functions have own scope, so we make it global, for this module, and childs. |
|||
Dim lines$() |
|||
s$=filter$(s$,chr$(9)) \\ exclude tabs |
|||
Lines$()=piece$(s$,nl$) \\ break to lines |
|||
lim=len(Lines$()) |
|||
Flush ' empty stack (there is a current stack of values which we use here) |
|||
Load_Ast() |
|||
If not stack.size=1 Then Flush : Error "Ast not loaded" |
|||
AST=array \\ pop the array from stack |
|||
Document Assembly$, Header$ |
|||
\\ all lines of assembly goes to stack. Maybe not in right order. |
|||
\\ Push statement push to top, Data statement push to bottom of stack |
|||
CodeGenerator(Ast) |
|||
Data code$("halt") ' append to end of stack |
|||
\\ So now we get all data (letters) from stack |
|||
While not empty |
|||
Assembly$=letter$+nl$ |
|||
end while |
|||
\\ So now we have to place them in order |
|||
Sort Assembly$ |
|||
\\ Let's make the header |
|||
Header$=format$("Datasize: {0} Strings: {1}", Len(Dataset),Len(strings))+nl$ |
|||
\\ we use an iterator object, str^ is the counter, readonly, but Eval$() use it from object. |
|||
str=each(strings) |
|||
While str |
|||
Header$=Eval$(str) |
|||
If str^<len(strings)-1 then Header$=nl$ |
|||
End while |
|||
\\ insert to line 1 the Header |
|||
Insert 1 Assembly$=Header$ |
|||
\\ Also we check for warnings |
|||
If len(message$)>2 then Assembly$="Warnings: "+nl$+message$ |
|||
\\ So now we get a report |
|||
\\ (at each 3/4 of window's lines, the printing stop and wait for user response, any key) |
|||
Report Assembly$ |
|||
Clipboard Assembly$ |
|||
Save.Doc Assembly$, "code.t", Ansi |
|||
End |
|||
\\ subs have 10000 limit for recursion but can be extended to 1000000 or more. |
|||
Sub CodeGenerator(t) |
|||
If len(t)=3 then |
|||
select case t#val(0) |
|||
Case gSeq |
|||
CodeGenerator(t#val(1)) : CodeGenerator(t#val(2)) |
|||
Case gwhile |
|||
{ |
|||
local spc=pc |
|||
CodeGenerator(t#val(1)) |
|||
local pc1=pc |
|||
pc+=5 ' room for jz |
|||
CodeGenerator(t#val(2)) |
|||
data code3$("jz",pc1, pc1, pc+5) |
|||
data code3$("jmp",pc, pc, spc) |
|||
pc+=5 ' room for jmp |
|||
} |
|||
Case gif |
|||
{ |
|||
CodeGenerator(t#val(1)) |
|||
local pc1=pc, pc2 |
|||
pc+=5 |
|||
CodeGenerator(t#val(2)#val(1)) |
|||
If len(t#val(2)#val(2))>0 then |
|||
pc2=pc |
|||
pc+=5 |
|||
data code3$("jz",pc1, pc1, pc) |
|||
CodeGenerator(t#val(2)#val(2)) |
|||
data code3$("jz",pc2, pc2, pc) |
|||
else |
|||
data code3$("jz",pc1, pc1, pc) |
|||
end If |
|||
} |
|||
Case gAssign |
|||
{ |
|||
CodeGenerator(t#val(2)) |
|||
local newvar_ok=true |
|||
CodeGenerator(t#val(1)) |
|||
} |
|||
case gneg to gnot, gputc to gprts |
|||
CodeGenerator(t#val(1)) : data code$(mid$(eval$(t#val(0)),2)) |
|||
case gmul to gor |
|||
{ |
|||
CodeGenerator(t#val(1)) |
|||
CodeGenerator(t#val(2)) |
|||
data code$(mid$(eval$(t#val(0)),2)) |
|||
} |
|||
End select |
|||
Else.if len(t)=2 then |
|||
select case t#val(0) |
|||
Case gString |
|||
{ |
|||
local spos |
|||
If exist(strings,t#val$(1)) then |
|||
spos=eval(strings!) |
|||
else |
|||
append strings, t#val$(1) |
|||
spos=len(strings)-1 |
|||
end If |
|||
Push code2$("push",str$(spos,0)) |
|||
} |
|||
Case gInt |
|||
Push code2$("push",t#val$(1), pc) |
|||
Case gIdentifier |
|||
{ |
|||
local ipos |
|||
If exist(dataset,t#val$(1)) then |
|||
ipos=Eval(dataset!) ' return position |
|||
else.if newvar_ok then |
|||
Append dataset, t#val$(1) |
|||
ipos=len(dataset)-1 |
|||
else |
|||
message$="Variable "+t#val$(1)+" not initialized"+nl$ |
|||
end If |
|||
If newvar_ok then |
|||
Push code2$("store","["+str$(ipos, 0)+"]") |
|||
else |
|||
Push code2$("fetch","["+str$(ipos, 0)+"]") |
|||
end If |
|||
} |
|||
end select |
|||
End If |
|||
End Sub |
|||
Sub Load_Ast() |
|||
If i>=lim then Push (,) : exit sub |
|||
do |
|||
line$=Trim$(lines$(i)) |
|||
I++ |
|||
tok$=piece$(line$," ")(0) |
|||
until line$<>"" or i>=lim |
|||
If tok$="Identifier" then |
|||
Push (gidentifier, piece$(line$," ")(1)) |
|||
else.if tok$="Integer" then |
|||
long n=Val(piece$(line$," ")(1)) ' check overflow |
|||
Push (gint, piece$(line$," ")(1)) |
|||
else.if tok$="String" then |
|||
Push (gstring,Trim$(Mid$(line$,7))) |
|||
else.if tok$=";" then |
|||
Push (,) |
|||
Else |
|||
local otok=symb(tok$) |
|||
Load_Ast() |
|||
Load_Ast() |
|||
Shift 2 |
|||
Push (otok,array, array) |
|||
End If |
|||
End Sub |
|||
} |
|||
CodeGenerator { |
|||
Sequence |
|||
Sequence |
|||
; |
|||
Assign |
|||
Identifier count |
|||
Integer 1 |
|||
While |
|||
Less |
|||
Identifier count |
|||
Integer 10 |
|||
Sequence |
|||
Sequence |
|||
; |
|||
Sequence |
|||
Sequence |
|||
Sequence |
|||
; |
|||
Prts |
|||
String "count is: " |
|||
; |
|||
Prti |
|||
Identifier count |
|||
; |
|||
Prts |
|||
String "\n" |
|||
; |
|||
Assign |
|||
Identifier count |
|||
Add |
|||
Identifier count |
|||
Integer 1 |
|||
} |
|||
</lang> |
|||
{{out}} |
|||
<pre style="height:30ex;overflow:scroll"> |
|||
Datasize: 1 Strings: 2 |
|||
"count is: " |
|||
"\n" |
|||
0 push |
|||
5 store [0] |
|||
10 fetch [0] |
|||
15 push |
|||
20 lt |
|||
21 jz (43) 65 |
|||
26 push 0 |
|||
31 prts |
|||
32 fetch [0] |
|||
37 prti |
|||
38 push 1 |
|||
43 prts |
|||
44 fetch [0] |
|||
49 push |
|||
54 add |
|||
55 store [0] |
|||
60 jmp (-51) 10 |
|||
65 halt |
|||
</pre > |
|||
=={{header|Perl}}== |
=={{header|Perl}}== |