This commit is contained in:
2025-10-12 01:41:37 +02:00
parent f6aef1f0d1
commit dbd7715193
11 changed files with 68 additions and 3 deletions

View File

@ -3,6 +3,7 @@ using System.IO;
using System.Text;
using System.Collections.Generic;
// === ENTRY POINT ===
class Program {
static int Main(string[] args) {
if (args.Length < 2) {
@ -31,6 +32,7 @@ public abstract class Stmt:StNode{}
public class AssignStmt:Stmt{ public string Target; public Expr Expr; }
public class IfStmt:Stmt{ public Expr Cond; public List<Stmt> ThenStmts=new(); public List<Stmt> ElseStmts=new(); }
public class WhileStmt:Stmt{ public Expr Cond; public List<Stmt> Body=new(); }
public class ForStmt:Stmt{ public string Var; public Expr Start, End, Step = new IntExpr(1); public List<Stmt> Body=new(); }
public abstract class Expr:StNode{}
public class IntExpr:Expr{ public int Value; public IntExpr(int v){Value=v;} }
@ -44,6 +46,7 @@ public enum TokType {
LT, GT, LE, GE, EQ, NEQ,
IF, THEN, ELSE, END_IF,
WHILE, DO, END_WHILE,
FOR, TO, BY, END_FOR,
PROGRAM, VAR, END_VAR, END_PROGRAM,
EOF
}
@ -75,6 +78,10 @@ public class StLexer {
"WHILE"=>new Token(TokType.WHILE,s),
"DO"=>new Token(TokType.DO,s),
"END_WHILE"=>new Token(TokType.END_WHILE,s),
"FOR"=>new Token(TokType.FOR,s),
"TO"=>new Token(TokType.TO,s),
"BY"=>new Token(TokType.BY,s),
"END_FOR"=>new Token(TokType.END_FOR,s),
_=>new Token(TokType.IDENT,s)
};
}
@ -151,6 +158,7 @@ public class StParser {
Stmt ParseStmt(){
if(cur.Type==TokType.IF) return ParseIf();
if(cur.Type==TokType.WHILE) return ParseWhile();
if(cur.Type==TokType.FOR) return ParseFor();
if(cur.Type==TokType.IDENT){
var n=cur.Text; Next(); Expect(TokType.ASSIGN);
var e=ParseExpr(); Expect(TokType.SEMI);
@ -184,6 +192,26 @@ public class StParser {
return ws;
}
ForStmt ParseFor(){
Next(); // FOR
string varName = cur.Text; Expect(TokType.IDENT);
Expect(TokType.ASSIGN);
Expr start = ParseExpr();
Expect(TokType.TO);
Expr end = ParseExpr();
Expr step = new IntExpr(1);
if(cur.Type==TokType.BY){
Next();
step = ParseExpr();
}
Expect(TokType.DO);
var fs = new ForStmt{Var=varName, Start=start, End=end, Step=step};
while(cur.Type!=TokType.END_FOR)
fs.Body.Add(ParseStmt());
Expect(TokType.END_FOR); Expect(TokType.SEMI);
return fs;
}
Expr ParseExpr()=>ParseCompare();
Expr ParseCompare(){
var l=ParseAddSub();
@ -233,7 +261,7 @@ public class BytecodeEmitter {
foreach(var s in p.Stmts)
EmitStmt(s);
EmitByte(0xF0);
EmitByte(0xF0); // Program End
}
void EmitStmt(Stmt s){
@ -264,6 +292,37 @@ public class BytecodeEmitter {
PatchJump(jzpos,code.Count);
break;
case ForStmt f:
// Initialisierung: var := start
EmitExpr(f.Start);
EmitByte(0x03); EmitU16((ushort)syms[f.Var].Index);
int cmpPos = code.Count; // Position des Vergleichs
EmitExpr(new VarExpr(f.Var));
EmitExpr(f.End);
EmitByte(0x16); // LE
EmitByte(0x20); int jzFor = code.Count; EmitU16(0); // Jump zum Ende
// Body
foreach(var st in f.Body) EmitStmt(st);
// Inkrement: i := i + step
EmitExpr(new VarExpr(f.Var));
EmitExpr(f.Step);
EmitByte(0x10); // PLUS
EmitByte(0x03); EmitU16((ushort)syms[f.Var].Index);
// Vergleich erneut, aber wir merken uns den Sprung zum Vergleich
EmitByte(0x21); EmitU16((ushort)cmpPos);
// Patch Jump: Ende der Schleife springt hierhin
PatchJump(jzFor, code.Count);
// Korrektur: Schleifenvariable auf Endwert, falls sie überläuft
EmitExpr(f.End);
EmitByte(0x03); EmitU16((ushort)syms[f.Var].Index);
break;
default: throw new Exception($"Unknown stmt {s.GetType().Name}");
}
}