Benutzer-Werkzeuge

Webseiten-Werkzeuge


tinypg

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen Revision Vorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
tinypg [2025/12/11 14:33]
jango
tinypg [2025/12/12 12:49] (aktuell)
jango [V4]
Zeile 1: Zeile 1:
 TinyPG TinyPG
  
 +In der Datei <code>Templates\C#\ParseTree.cs</code> in der Klasse ParseTree folgendes Property dazu!
 <code> <code>
-<% @TinyPG Language="c#" OutputPath="C:\chroot\Parser\" %>+public Dictionary<string, int> Variables  new Dictionary<string, int>(); 
 +</code>
  
-NUMBER -> @"[0-9]+"; +=====V1=====
-PLUSMINUS -> @"(\+|-)"; +
-MULTDIV -> @"\*|/"; +
-BROPEN ->  @"\("; +
-BRCLOSE ->  @"\)"; +
-EOF         -> @"^$";+
  
-[Skip] WHITESPACE  -> @"\s+";+<code> 
 +//@TinyPG - a Tiny Parser Generator v1.2 
 +// Mini-Skriptsprache: print, Variablen, while
  
-Start  -> (AddExpr)? EOF+<% @TinyPG Language="C#" Namespace="MyScript" OutputPath="C:\Users\manuel.zarat\source\repos\ConsoleApp1\ConsoleApp1" %> 
-AddExpr  -> MultExpr (PLUSMINUS MultExpr)*; + 
-MultExpr  -> Atom (MULTDIV Atom)*; +// Tokens (Reihenfolge ist wichtig!) 
-Atom  -> NUMBER | BROPEN AddExpr BRCLOSE;+ 
 +EOF                 -> @"^\s*$"; 
 +[Color(255, 0, 0)]  NUMBER      -> @"[0-9]+"; 
 +[Color(0, 0, 255)]  PLUSMINUS   -> @"(\+|-)"; 
 +[Color(0, 0, 255)]  MULTDIV     -> @"\*|/"; 
 +[Color(0, 0, 255)]  BROPEN      -> @"\("; 
 +[Color(0, 0, 255)]  BRCLOSE     -> @"\)"; 
 +[Color(0, 0, 255)]  ASSIGN      -> @"="; 
 + 
 +// Keywords – MÜSSEN VOR IDENT kommen! 
 +[Color(0, 128, 0)]  PRINT       -> @"print"; 
 +[Color(0, 128, 0)]  LET         -> @"let"; 
 +[Color(0, 128, 0)]  WHILE       -> @"while"; 
 +[Color(0, 128, 0)]  DO          -> @"do"; 
 +[Color(0, 128, 0)]  END         -> @"end"; 
 + 
 +// Bezeichner 
 +[Color(128, 0, 128)] IDENT      -> @"[a-zA-Z_][a-zA-Z0-9_]*"; 
 + 
 +[Skip] WHITESPACE   -> @"\s+"; 
 + 
 +// --------- Grammatik --------- 
 + 
 +// Ein Programm ist eine Liste von Statements 
 +Start -> StmtList EOF 
 +
 +    return $StmtList; 
 +}; 
 + 
 +// Liste von Statements 
 +StmtList -> (Stmt)* 
 +
 +    // WICHTIG: wir laufen direkt über die Kindknoten, 
 +    // damit jedes Stmt genau einmal evaluiert wird. 
 +    foreach (ParseNode node in nodes) 
 +    { 
 +        if (node.Token.Type == TokenType.Stmt) 
 +            node.Eval(tree); 
 +    } 
 +    return null; 
 +}; 
 + 
 +// Ein Statement kann print, let oder while sein 
 +Stmt -> PrintStmt 
 +      | LetStmt 
 +      | WhileStmt 
 +
 + 
 +// print-Ausgabe 
 +PrintStmt -> PRINT AddExpr 
 +
 +    int value = Convert.ToInt32($AddExpr); 
 +    Console.WriteLine(value); 
 +    return null; 
 +}; 
 + 
 +// Variablenzuweisung: let x = 3+4 
 +LetStmt -> LET IDENT ASSIGN AddExpr 
 +
 +    string name = $IDENT.ToString(); 
 +    int value = Convert.ToInt32($AddExpr); 
 + 
 +    if (!tree.Variables.ContainsKey(name)) 
 +        tree.Variables.Add(name, value); 
 +    else 
 +        tree.Variables[name] = value; 
 + 
 +    return null; 
 +}; 
 + 
 +// while-Schleife: while <expr> do <stmts> end 
 +// Schleife läuft, solange Ausdruck != 0 ist 
 +WhileStmt -> WHILE AddExpr DO StmtList END 
 +
 +    while (Convert.ToInt32($AddExpr) != 0) 
 +    { 
 +        // Body neu ausführen 
 +        $StmtList; 
 +    } 
 +    return null; 
 +}; 
 + 
 +// ---------- Ausdrücke ---------- 
 + 
 +AddExpr -> MultExpr (PLUSMINUS MultExpr)* 
 +{  
 +    int Value = Convert.ToInt32($MultExpr); 
 +    int i = 1; 
 +    while ($MultExpr[i] != null) 
 +    { 
 +        string sign = $PLUSMINUS[i-1].ToString(); 
 +        if (sign == "+"
 +            Value += Convert.ToInt32($MultExpr[i++]); 
 +        else  
 +            Value -= Convert.ToInt32($MultExpr[i++]); 
 +    } 
 + 
 +    return Value;  
 +}; 
 + 
 +MultExpr -> Atom (MULTDIV Atom)* 
 +{  
 +    int Value = Convert.ToInt32($Atom); 
 +    int i = 1; 
 +    while ($Atom[i] != null) 
 +    { 
 +        string sign = $MULTDIV[i-1].ToString(); 
 +        if (sign == "*"
 +            Value *= Convert.ToInt32($Atom[i++]); 
 +        else  
 +            Value /= Convert.ToInt32($Atom[i++]); 
 +    } 
 +    return Value;  
 +}; 
 + 
 +// Atom: Zahl, Variable oder (Ausdruck) 
 +Atom -> NUMBER | IDENT | BROPEN AddExpr BRCLOSE 
 +
 +    if ($NUMBER != null) 
 +        return $NUMBER; 
 + 
 +    if ($IDENT != null) 
 +    { 
 +        string name = $IDENT.ToString(); 
 +        if (tree.Variables.ContainsKey(name)) 
 +            return tree.Variables[name]; 
 +        else 
 +            throw new Exception("Undefined variable: " + name); 
 +    } 
 + 
 +    // Klammer-Ausdruck 
 +    return $AddExpr;  
 +};
 </code> </code>
  
 <code> <code>
 +let x = 13
  
-// Simple expression calculator with print + strings + variables +while x do 
-<% @TinyPG Language="C#" Namespace="MyScript" OutputPath="C:\Users\manuel.zarat\source\repos\ConsoleApp1\ConsoleApp1\"  %>+    print x 
 +    let x x - 1 
 +end
  
 +print x
 +</code>
 +
 +
 +=====V2=====
 +
 +if/else dazu
 +
 +<code>
 +//@TinyPG - a Tiny Parser Generator v1.2
 +// Mini-Skriptsprache: print, Variablen, while
 +
 +<% @TinyPG Language="C#" Namespace="MyScript" OutputPath="C:\Users\manuel.zarat\source\repos\ConsoleApp1\ConsoleApp1" %>
 +
 +// Tokens (Reihenfolge ist wichtig!)
 +
 +EOF                 -> @"^\s*$";
 +[Color(255, 0, 0)]  NUMBER      -> @"[0-9]+";
 +[Color(0, 0, 255)]  PLUSMINUS   -> @"(\+|-)";
 +[Color(0, 0, 255)]  MULTDIV     -> @"\*|/";
 +[Color(0, 0, 255)]  BROPEN      -> @"\(";
 +[Color(0, 0, 255)]  BRCLOSE     -> @"\)";
 +[Color(0, 0, 255)]  ASSIGN      -> @"=";
 +
 +// Keywords – MÜSSEN VOR IDENT kommen!
 +[Color(0, 128, 0)]  PRINT       -> @"print";
 +[Color(0, 128, 0)]  LET         -> @"let";
 +[Color(0, 128, 0)]  WHILE       -> @"while";
 +[Color(0, 128, 0)]  DO          -> @"do";
 +[Color(0, 128, 0)]  END         -> @"end";
 +[Color(0, 128, 0)]  IF          -> @"if";
 +[Color(0, 128, 0)]  ELSE        -> @"else";
 +
 +// Bezeichner
 +[Color(128, 0, 128)] IDENT      -> @"[a-zA-Z_][a-zA-Z0-9_]*";
 +
 +[Skip] WHITESPACE   -> @"\s+";
 +
 +// --------- Grammatik ---------
 +
 +// Ein Programm ist eine Liste von Statements
 +Start -> StmtList EOF
 +{
 +    return $StmtList;
 +};
 +
 +// Liste von Statements
 +StmtList -> (Stmt)*
 +{
 +    // WICHTIG: wir laufen direkt über die Kindknoten,
 +    // damit jedes Stmt genau einmal evaluiert wird.
 +    foreach (ParseNode node in nodes)
 +    {
 +        if (node.Token.Type == TokenType.Stmt)
 +            node.Eval(tree);
 +    }
 +    return null;
 +};
 +
 +// Ein Statement kann print, let oder while sein
 +Stmt -> PrintStmt
 +      | LetStmt
 +      | WhileStmt
 +      | IfStmt
 +;
 +
 +// print-Ausgabe
 +PrintStmt -> PRINT AddExpr
 +{
 +    int value = Convert.ToInt32($AddExpr);
 +    Console.WriteLine(value);
 +    return null;
 +};
 +
 +// Variablenzuweisung: let x = 3+4
 +LetStmt -> LET IDENT ASSIGN AddExpr
 +{
 +    string name = $IDENT.ToString();
 +    int value = Convert.ToInt32($AddExpr);
 +
 +    if (!tree.Variables.ContainsKey(name))
 +        tree.Variables.Add(name, value);
 +    else
 +        tree.Variables[name] = value;
 +
 +    return null;
 +};
 +
 +// while-Schleife: while <expr> do <stmts> end
 +// Schleife läuft, solange Ausdruck != 0 ist
 +WhileStmt -> WHILE AddExpr DO StmtList END
 +{
 +    while (Convert.ToInt32($AddExpr) != 0)
 +    {
 +        // Body neu ausführen
 +        $StmtList;
 +    }
 +    return null;
 +};
 +
 +// if: if <expr> do <stmts> (else <stmts>)? end
 +// True, wenn Ausdruck != 0
 +IfStmt -> IF AddExpr DO StmtList (ELSE StmtList)? END
 +{
 +    if (Convert.ToInt32($AddExpr) != 0)
 +    {
 +        // then-Block
 +        $StmtList[0];
 +    }
 +    else
 +    {
 +        // else-Block (falls vorhanden)
 +        if ($StmtList[1] != null)
 +            $StmtList[1];
 +    }
 +    return null;
 +};
 +
 +// ---------- Ausdrücke ----------
 +
 +AddExpr -> MultExpr (PLUSMINUS MultExpr)*
 +
 +    int Value = Convert.ToInt32($MultExpr);
 +    int i = 1;
 +    while ($MultExpr[i] != null)
 +    {
 +        string sign = $PLUSMINUS[i-1].ToString();
 +        if (sign == "+")
 +            Value += Convert.ToInt32($MultExpr[i++]);
 +        else 
 +            Value -= Convert.ToInt32($MultExpr[i++]);
 +    }
 +
 +    return Value; 
 +};
 +
 +MultExpr -> Atom (MULTDIV Atom)*
 +
 +    int Value = Convert.ToInt32($Atom);
 +    int i = 1;
 +    while ($Atom[i] != null)
 +    {
 +        string sign = $MULTDIV[i-1].ToString();
 +        if (sign == "*")
 +            Value *= Convert.ToInt32($Atom[i++]);
 +        else 
 +            Value /= Convert.ToInt32($Atom[i++]);
 +    }
 +    return Value; 
 +};
 +
 +// Atom: Zahl, Variable oder (Ausdruck)
 +Atom -> NUMBER | IDENT | BROPEN AddExpr BRCLOSE
 +{
 +    if ($NUMBER != null)
 +        return $NUMBER;
 +
 +    if ($IDENT != null)
 +    {
 +        string name = $IDENT.ToString();
 +        if (tree.Variables.ContainsKey(name))
 +            return tree.Variables[name];
 +        else
 +            throw new Exception("Undefined variable: " + name);
 +    }
 +
 +    // Klammer-Ausdruck
 +    return $AddExpr; 
 +};
 +</code>
 +
 +<code>
 +let x = 13
 +let y = 2
 +
 +while x do
 +    print x
 +    let x = x - y
 +
 +    if x < 1do
 + print x
 +    end
 +end
 +print x
 +</code>
 +
 +
 +=====V3=====
 +
 +Mit Vergleichsoperatoren
 +
 +<code>
 +//@TinyPG - a Tiny Parser Generator v1.2
 +// Mini-Skriptsprache: print, Variablen, while
 +
 +<% @TinyPG Language="C#" Namespace="MyScript" OutputPath="C:\Users\manuel.zarat\source\repos\ConsoleApp1\ConsoleApp1" %>
 +
 +// Tokens (Reihenfolge ist wichtig!)
 +
 +EOF                 -> @"^\s*$";
 +[Color(255, 0, 0)]  NUMBER      -> @"[0-9]+";
 +[Color(0, 0, 255)]  PLUSMINUS   -> @"(\+|-)";
 +[Color(0, 0, 255)]  MULTDIV     -> @"\*|/";
 +[Color(0, 0, 255)]  BROPEN      -> @"\(";
 +[Color(0, 0, 255)]  BRCLOSE     -> @"\)";
 +[Color(0, 0, 255)]  RELOP       -> @"(<=|>=|==|!=|<|>)";
 +[Color(0, 0, 255)]  ASSIGN      -> @"=";
 +
 +// Keywords – MÜSSEN VOR IDENT kommen!
 +[Color(0, 128, 0)]  PRINT       -> @"print";
 +[Color(0, 128, 0)]  LET         -> @"let";
 +[Color(0, 128, 0)]  WHILE       -> @"while";
 +[Color(0, 128, 0)]  DO          -> @"do";
 +[Color(0, 128, 0)]  END         -> @"end";
 +[Color(0, 128, 0)]  IF          -> @"if";
 +[Color(0, 128, 0)]  ELSE        -> @"else";
 +
 +// Bezeichner
 +[Color(128, 0, 128)] IDENT      -> @"[a-zA-Z_][a-zA-Z0-9_]*";
 +
 +[Skip] WHITESPACE   -> @"\s+";
 +
 +// --------- Grammatik ---------
 +
 +// Ein Programm ist eine Liste von Statements
 +Start -> StmtList EOF
 +{
 +    return $StmtList;
 +};
 +
 +// Liste von Statements
 +StmtList -> (Stmt)*
 +{
 +    // WICHTIG: wir laufen direkt über die Kindknoten,
 +    // damit jedes Stmt genau einmal evaluiert wird.
 +    foreach (ParseNode node in nodes)
 +    {
 +        if (node.Token.Type == TokenType.Stmt)
 +            node.Eval(tree);
 +    }
 +    return null;
 +};
 +
 +// Ein Statement kann print, let oder while sein
 +Stmt -> PrintStmt
 +      | LetStmt
 +      | WhileStmt
 +      | IfStmt
 +;
 +
 +// print-Ausgabe
 +PrintStmt -> PRINT CondExpr
 +{
 +    int value = Convert.ToInt32($CondExpr);
 +    Console.WriteLine(value);
 +    return null;
 +};
 +
 +LetStmt -> LET IDENT ASSIGN CondExpr
 +{
 +    string name = $IDENT.ToString();
 +    int value = Convert.ToInt32($CondExpr);
 +
 +    if (!tree.Variables.ContainsKey(name))
 +        tree.Variables.Add(name, value);
 +    else
 +        tree.Variables[name] = value;
 +
 +    return null;
 +};
 +
 +// while-Schleife: while <expr> do <stmts> end
 +// Schleife läuft, solange Ausdruck != 0 ist
 +WhileStmt -> WHILE CondExpr DO StmtList END
 +{
 +    while (Convert.ToInt32($CondExpr) != 0)
 +    {
 +        $StmtList;
 +    }
 +    return null;
 +};
 +
 +
 +// ---------- Bedingungen / Vergleiche ----------
 +// Liefert int: true=1, false=0
 +CondExpr -> AddExpr (RELOP AddExpr)?
 +{
 +    int left = Convert.ToInt32($AddExpr[0]);
 +
 +    // kein Vergleich -> normaler Zahlenwert (wie bisher)
 +    if ($RELOP == null)
 +        return left;
 +
 +    int right = Convert.ToInt32($AddExpr[1]);
 +    string op = $RELOP.ToString();
 +
 +    bool result =
 +        (op == "<"  && left <  right) ||
 +        (op == "<=" && left <= right) ||
 +        (op == ">"  && left >  right) ||
 +        (op == ">=" && left >= right) ||
 +        (op == "==" && left == right) ||
 +        (op == "!=" && left != right);
 +
 +    return result ? 1 : 0;
 +};
 +
 +
 +// if: if <expr> do <stmts> (else <stmts>)? end
 +// True, wenn Ausdruck != 0
 +IfStmt -> IF CondExpr DO StmtList (ELSE StmtList)? END
 +{
 +    if (Convert.ToInt32($CondExpr) != 0)
 +        $StmtList[0];
 +    else
 +    {
 +        if ($StmtList[1] != null)
 +            $StmtList[1];
 +    }
 +    return null;
 +};
 +
 +// ---------- Ausdrücke ----------
 +
 +AddExpr -> MultExpr (PLUSMINUS MultExpr)*
 +
 +    int Value = Convert.ToInt32($MultExpr);
 +    int i = 1;
 +    while ($MultExpr[i] != null)
 +    {
 +        string sign = $PLUSMINUS[i-1].ToString();
 +        if (sign == "+")
 +            Value += Convert.ToInt32($MultExpr[i++]);
 +        else 
 +            Value -= Convert.ToInt32($MultExpr[i++]);
 +    }
 +
 +    return Value; 
 +};
 +
 +MultExpr -> Atom (MULTDIV Atom)*
 +
 +    int Value = Convert.ToInt32($Atom);
 +    int i = 1;
 +    while ($Atom[i] != null)
 +    {
 +        string sign = $MULTDIV[i-1].ToString();
 +        if (sign == "*")
 +            Value *= Convert.ToInt32($Atom[i++]);
 +        else 
 +            Value /= Convert.ToInt32($Atom[i++]);
 +    }
 +    return Value; 
 +};
 +
 +// Atom: Zahl, Variable oder (Ausdruck)
 +Atom -> NUMBER | IDENT | BROPEN AddExpr BRCLOSE
 +{
 +    if ($NUMBER != null)
 +        return $NUMBER;
 +
 +    if ($IDENT != null)
 +    {
 +        string name = $IDENT.ToString();
 +        if (tree.Variables.ContainsKey(name))
 +            return tree.Variables[name];
 +        else
 +            throw new Exception("Undefined variable: " + name);
 +    }
 +
 +    // Klammer-Ausdruck
 +    return $AddExpr; 
 +};
 +</code>
 +
 +<code>
 +let x = 0
 +while x < 5 do
 +  print x
 +  let x = x + 1
 +end
 +
 +if x == 5 do
 +  print 999
 +else
 +  print 111
 +end
 +</code>
 +
 +
 +=====V4=====
 +
 +Mit Strings
 +
 +<code>
 +//@TinyPG - a Tiny Parser Generator v1.2
 +// Mini-Skriptsprache: print, let, while, if/else
 +// int + string, '+' kann concat, RELOP auch für Strings
 +
 +<% @TinyPG Language="C#" Namespace="MyScript" OutputPath="C:\Users\manuel.zarat\source\repos\ConsoleApp1\ConsoleApp1" %>
 +
 +// ---------------- Tokens ----------------
 +
 +EOF                 -> @"^\s*$";
  
-// -------- Tokens -------- 
-EOF                  -> @"^\s*$"; 
 [Color(255, 0, 0)]   NUMBER     -> @"[0-9]+"; [Color(255, 0, 0)]   NUMBER     -> @"[0-9]+";
-[Color(1632121)] STRING     -> @"""[^""]*"""; +[Color(2551280)] STRING     -> @"""([^""\\]|\\.)*"""; 
-[Color(128, 0, 128)] PRINT      -> @"print"; +
-[Color(0, 128, 0)]   IDENT      -> @"[a-zA-Z_][a-zA-Z0-9_]*"; +
-[Color(0, 0, 255)]   ASSIGN     -> @"=";+
 [Color(0, 0, 255)]   PLUSMINUS  -> @"(\+|-)"; [Color(0, 0, 255)]   PLUSMINUS  -> @"(\+|-)";
-[Color(0, 0, 255)]   MULTDIV    -> @"\*|/";+[Color(0, 0, 255)]   MULTDIV    -> @"(\*|/)";
 [Color(0, 0, 255)]   BROPEN     -> @"\("; [Color(0, 0, 255)]   BROPEN     -> @"\(";
 [Color(0, 0, 255)]   BRCLOSE    -> @"\)"; [Color(0, 0, 255)]   BRCLOSE    -> @"\)";
 +[Color(0, 0, 255)]   RELOP      -> @"(<=|>=|==|!=|<|>)";
 +[Color(0, 0, 255)]   ASSIGN     -> @"=";
  
-[Skip              WHITESPACE -> @"\s+";+// Keywords – MÜSSEN VOR IDENT kommen! 
 +[Color(0, 128, 0)  PRINT      -> @"print"; 
 +[Color(0, 128, 0)]   LET        -> @"let"; 
 +[Color(0, 128, 0)]   WHILE      -> @"while"; 
 +[Color(0, 128, 0)]   DO         -> @"do"; 
 +[Color(0, 128, 0)]   END        -> @"end"; 
 +[Color(0, 128, 0)]   IF         -> @"if"; 
 +[Color(0, 128, 0)]   ELSE       -> @"else";
  
-// ======================= +[Color(128, 0, 128)] IDENT      -> @"[a-zA-Z_][a-zA-Z0-9_]*";
-//   Grammatik / Semantik +
-// =======================+
  
-// mehrere Statements; Result ist uns egal -> null +[Skip] WHITESPACE    -> @"\s+"; 
-Start -> (Statement)* EOF+ 
 + 
 +// ---------------- Grammatik ---------------- 
 + 
 +Start -> StmtList EOF
 { {
 +    return $StmtList;
 +};
  
- string output "";  +StmtList -> (Stmt)* 
- int i = 0+
 +    foreach (ParseNode node in nodes) 
 +    { 
 +        if (node.Token.Type == TokenType.Stmt) 
 +            node.Eval(tree)
 +    } 
 +    return null; 
 +};
  
- while ($Statement[i] != null) { +Stmt -> PrintStmt 
 +      | LetStmt 
 +      | WhileStmt 
 +      | IfStmt 
 +;
  
- if ($Statement[i] != null) {  +// ---------------- Statements ----------------
- if (output.Length > 0)  +
- output += "\r\n";  +
- output += $Statement[i].ToString();  +
- }  +
- i++; +
- }  +
-  +
- return output;+
  
 +PrintStmt -> PRINT Expr
 +{
 +    object v = $Expr;
 +    Console.WriteLine(v == null ? "null" : v.ToString());
 +    return null;
 }; };
  
-Statement -> AssignStmt | PrintStmt | ExprStmt+LetStmt -> LET IDENT ASSIGN Expr
 { {
-    if ($AssignStmt !nullreturn $AssignStmt+    string name $IDENT.ToString()
-    if ($PrintStmt  != nullreturn $PrintStmt+    object value = $Expr; 
-    return $ExprStmt;+ 
 +    // tree.Variables: Dictionary<string, object> 
 +    if (!tree.Variables.ContainsKey(name)) 
 +        tree.Variables.Add(name, value); 
 +    else 
 +        tree.Variables[name] = value; 
 + 
 +    return null;
 }; };
  
-// a = 12  oder  a = "Hallo"  oder  a = 1+2*3 +WhileStmt -> WHILE CondExpr DO StmtList END
-AssignStmt -> IDENT ASSIGN AddExpr+
 { {
-    // "Variables" kommt aus der partiellen Parser-Klasse (siehe unten) +    while (Convert.ToInt32($CondExpr!0) 
-    Variables[$IDENT.ToString()= $AddExpr;+    { 
 +        $StmtList; 
 +    }
     return null;     return null;
 }; };
  
-// print( Ausdruck ) +IfStmt -> IF CondExpr DO StmtList (ELSE StmtList)? END
-PrintStmt -> PRINT BROPEN AddExpr BRCLOSE+
 { {
-    Console.WriteLine($AddExpr);+    if (Convert.ToInt32($CondExpr!= 0) 
 +        $StmtList[0]; 
 +    else 
 +    { 
 +        if ($StmtList[1] != null) 
 +            $StmtList[1]; 
 +    }
     return null;     return null;
 }; };
  
-// nackter Ausdruck als Statement + 
-ExprStmt -> AddExpr+// ---------------- Bedingungen / Vergleiche ---------------- 
 +// Ergebnis: int (true=1, false=0) 
 +CondExpr -> AddExpr (RELOP AddExpr)? 
 +
 +    object left = $AddExpr[0]; 
 + 
 +    // ohne Vergleich: truthy 
 +    if ($RELOP == null) 
 +    { 
 +        if (left == null) return 0; 
 +        if (left is int) return ((int)left != 0) ? 1 : 0; 
 +        if (left is bool) return ((bool)left) ? 1 : 0; 
 +        if (left is string) return (((string)left).Length != 0) ? 1 : 0; 
 +        return 1; 
 +    } 
 + 
 +    object right = $AddExpr[1]; 
 +    string op = $RELOP.ToString(); 
 + 
 +    // int vs int 
 +    if (left is int && right is int) 
 +    { 
 +        int l = (int)left; 
 +        int r = (int)right; 
 + 
 +        bool res = 
 +            (op == "<"  && l <  r) || 
 +            (op == "<=" && l <= r) || 
 +            (op == ">"  && l >  r) || 
 +            (op == ">=" && l >= r) || 
 +            (op == "==" && l == r) || 
 +            (op == "!=" && l != r); 
 + 
 +        return res ? 1 : 0; 
 +    } 
 + 
 +    // string vs string (ordinal) 
 +    if (left is string && right is string) 
 +    { 
 +        int cmp = string.CompareOrdinal((string)left, (string)right); 
 + 
 +        bool res = 
 +            (op == "<"  && cmp <  0) || 
 +            (op == "<=" && cmp <= 0) || 
 +            (op == ">"  && cmp >  0) || 
 +            (op == ">=" && cmp >= 0) || 
 +            (op == "==" && cmp == 0) || 
 +            (op == "!=" && cmp != 0); 
 + 
 +        return res ? 1 : 0; 
 +    } 
 + 
 +    // gemischte Typen: == / != ok, Ordnung nicht 
 +    if (op == "==") return 0; 
 +    if (op == "!=") return 1; 
 + 
 +    throw new Exception( 
 +        "Invalid comparison between '"
 +        (left == null ? "null" : left.GetType().Name) + 
 +        "' and '"
 +        (right == null ? "null" : right.GetType().Name) + 
 +        "' using '" + op + "'." 
 +    ); 
 +}; 
 + 
 + 
 +// ---------------- Ausdrücke ---------------- 
 + 
 +Expr -> AddExpr
 { {
     return $AddExpr;     return $AddExpr;
 }; };
  
-// Addition / Subtraktion 
-// +: Zahlen addieren ODER Strings konkatenieren 
 AddExpr -> MultExpr (PLUSMINUS MultExpr)* AddExpr -> MultExpr (PLUSMINUS MultExpr)*
-+{
     object value = $MultExpr;     object value = $MultExpr;
     int i = 1;     int i = 1;
Zeile 106: Zeile 740:
         if (sign == "+")         if (sign == "+")
         {         {
 +            // concat wenn einer string ist
             if (value is string || rhs is string)             if (value is string || rhs is string)
-                value = value.ToString() rhs.ToString();+            { 
 +                string ls = (value == null) ? ""value.ToString()
 +                string rs = (rhs   == null) ? ""rhs.ToString(); 
 +                value = ls + rs; 
 +            }
             else             else
-                value = Convert.ToInt32(value) + Convert.ToInt32(rhs);+            { 
 +                // beide müssen int sein 
 +                if (!(value is int|| !(rhs is int)) 
 +                    throw new Exception("Operator '+' erwartet Zahl+Zahl oder String-Konkatenation."); 
 +                value = (int)value + (int)rhs; 
 +            }
         }         }
-        else // "-"+        else
         {         {
-            value = Convert.ToInt32(value) - Convert.ToInt32(rhs);+            // '-' nur numerisch 
 +            if (!(value is int|| !(rhs is int)) 
 +                throw new Exception("Operator '-' ist nur für Zahlen erlaubt."); 
 +            value = (int)value - (int)rhs;
         }         }
     }     }
  
-    return value; +    return value;
 }; };
  
-// Multiplikation / Division (nur numerisch) 
 MultExpr -> Atom (MULTDIV Atom)* MultExpr -> Atom (MULTDIV Atom)*
-{  +
-    object value = $Atom;+    object accObj = $Atom
 + 
 +    // Wenn kein * oder / folgt, dürfen wir int ODER string einfach durchreichen 
 +    if ($Atom[1] == null) 
 +        return accObj; 
 + 
 +    // Sobald * oder / vorkommt: nur Zahlen erlaubt 
 +    if (!(accObj is int)) 
 +        throw new Exception("Operator '*' und '/' sind nur für Zahlen erlaubt."); 
 + 
 +    int acc = (int)accObj;
     int i = 1;     int i = 1;
  
Zeile 129: Zeile 785:
     {     {
         string sign = $MULTDIV[i-1].ToString();         string sign = $MULTDIV[i-1].ToString();
-        object rhs = $Atom[i++];+        object rhsObj = $Atom[i++]
 + 
 +        if (!(rhsObj is int)) 
 +            throw new Exception("Operator '*' und '/' sind nur für Zahlen erlaubt."); 
 + 
 +        int rhs = (int)rhsObj;
  
         if (sign == "*")         if (sign == "*")
 +            acc *= rhs;
 +        else
 +            acc /= rhs;
 +    }
 +
 +    return acc;
 +};
 +
 +Atom -> NUMBER | STRING | IDENT | BROPEN Expr BRCLOSE
 +{
 +    if ($NUMBER != null)
 +        return Convert.ToInt32($NUMBER.ToString());
 +
 +    if ($STRING != null)
 +    {
 +        string raw = $STRING.ToString();
 +        raw = raw.Substring(1, raw.Length - 2);
 +
 +        System.Text.StringBuilder sb = new System.Text.StringBuilder();
 +        for (int j = 0; j < raw.Length; j++)
         {         {
-            value Convert.ToInt32(value* Convert.ToInt32(rhs);+            char c raw[j]; 
 +            if (c == '\\' && j + 1 < raw.Length) 
 +            { 
 +                char n = raw[++j]; 
 +                if      (n == 'n'sb.Append('\n'); 
 +                else if (n == 't') sb.Append('\t'); 
 +                else if (n == 'r') sb.Append('\r'); 
 +                else if (n == '\\') sb.Append('\\'); 
 +                else if (n == '"') sb.Append('"'); 
 +                else sb.Append(n); 
 +            } 
 +            else 
 +            { 
 +                sb.Append(c); 
 +            }
         }         }
-        else // "/"+ 
 +        return sb.ToString(); 
 +    } 
 + 
 +    if ($IDENT != null) 
 +    { 
 +        string name = $IDENT.ToString(); 
 +        if (tree.Variables.ContainsKey(name)) 
 +            return tree.Variables[name]; 
 +        throw new Exception("Undefined variable: " + name); 
 +    } 
 + 
 +    return $Expr; 
 +}; 
 +</code> 
 + 
 +<code> 
 +let x = 0 
 +let y = "Check" 
 +while x < 5 do 
 +  print x 
 +  let x = x + 1 
 + 
 +  if x > 3 do 
 +    print y 
 +  end 
 +end 
 +</code> 
 + 
 + 
 +=====V5===== 
 + 
 +Switch/Case 
 + 
 +<code> 
 +//@TinyPG - a Tiny Parser Generator v1.2 
 +// Mini-Skriptsprache: print, let, while, if/else 
 +// int + string, '+' kann concat, RELOP auch für Strings 
 + 
 +<% @TinyPG Language="C#" Namespace="MyScript" OutputPath="C:\Users\manuel.zarat\source\repos\ConsoleApp1\ConsoleApp1" %> 
 + 
 +// ---------------- Tokens ---------------- 
 + 
 +EOF                 -> @"^\s*$"; 
 + 
 +[Color(255, 0, 0)]   NUMBER     -> @"[0-9]+"; 
 +[Color(255, 128, 0)] STRING     -> @"""([^""\\]|\\.)*"""; 
 + 
 +[Color(0, 0, 255)]   PLUSMINUS  -> @"(\+|-)"; 
 +[Color(0, 0, 255)]   MULTDIV    -> @"(\*|/)"; 
 +[Color(0, 0, 255)]   BROPEN     -> @"\("; 
 +[Color(0, 0, 255)]   BRCLOSE    -> @"\)"; 
 +[Color(0, 0, 255)]   RELOP      -> @"(<=|>=|==|!=|<|>)"; 
 +[Color(0, 0, 255)]   ASSIGN     -> @"="; 
 + 
 +// Keywords – MÜSSEN VOR IDENT kommen! 
 +[Color(0, 128, 0)]   PRINT      -> @"print"; 
 +[Color(0, 128, 0)]   LET        -> @"let"; 
 +[Color(0, 128, 0)]   WHILE      -> @"while"; 
 +[Color(0, 128, 0)]   DO         -> @"do"; 
 +[Color(0, 128, 0)]   END        -> @"end"; 
 +[Color(0, 128, 0)]   IF         -> @"if"; 
 +[Color(0, 128, 0)]   ELSE       -> @"else"; 
 +[Color(0, 128, 0)]   SWITCH      -> @"switch"; 
 +[Color(0, 128, 0)]   CASE        -> @"case"; 
 + 
 +[Color(128, 0, 128)] IDENT      -> @"[a-zA-Z_][a-zA-Z0-9_]*"; 
 + 
 +[Skip] WHITESPACE    -> @"\s+"; 
 + 
 + 
 +// ---------------- Grammatik ---------------- 
 + 
 +Start -> StmtList EOF 
 +
 +    return $StmtList; 
 +}; 
 + 
 +StmtList -> (Stmt)* 
 +
 +    foreach (ParseNode node in nodes) 
 +    { 
 +        if (node.Token.Type == TokenType.Stmt) 
 +            node.Eval(tree); 
 +    } 
 +    return null; 
 +}; 
 + 
 +Stmt -> PrintStmt 
 +      | LetStmt 
 +      | WhileStmt 
 +      | IfStmt 
 +      | SwitchStmt 
 +
 + 
 +// ---------------- Statements ---------------- 
 + 
 +// switch <expr> do (case <expr> do <stmts>)* (else <stmts>)? end 
 +SwitchStmt -> SWITCH Expr DO (CASE Expr DO StmtList)* (ELSE StmtList)? END 
 +
 +    object key = $Expr[0];     // switch-key 
 +    int i = 1;                 // Expr[1..] sind case-werte 
 +    int caseBodyIndex = 0;     // StmtList[0..] sind case-bodies, danach optional else 
 + 
 +    while ($Expr[i] != null) 
 +    { 
 +        object cv = $Expr[i]; 
 + 
 +        bool match = false; 
 + 
 +        if (key is int && cv is int) 
 +            match = ((int)key == (int)cv); 
 +        else if (key is string && cv is string) 
 +            match = (string.CompareOrdinal((string)key, (string)cv) == 0); 
 +        else 
 +            match = false; // gemischte Typen: kein Match 
 + 
 +        if (match)
         {         {
-            value = Convert.ToInt32(value) Convert.ToInt32(rhs);+            // genau den passenden case-body ausführen 
 +            $StmtList[caseBodyIndex]; 
 +            return null;
         }         }
 +
 +        i++;
 +        caseBodyIndex++;
     }     }
-    return value+ 
 +    // else-body (falls vorhanden) ist das nächste StmtList nach den case-bodies 
 +    if ($StmtList[caseBodyIndex] != null) 
 +        $StmtList[caseBodyIndex]; 
 + 
 +    return null;
 }; };
  
-// Atome: Zahl, String, Variable oder (Ausdruck) +PrintStmt -> PRINT Expr
-Atom -> NUMBER | STRING | IDENT | BROPEN AddExpr BRCLOSE+
 { {
-    if ($NUMBER != null)+    object v = $Expr; 
 +    Console.WriteLine(v == null ? "null" : v.ToString()); 
 +    return null; 
 +}; 
 + 
 +LetStmt -> LET IDENT ASSIGN Expr 
 +
 +    string name = $IDENT.ToString(); 
 +    object value = $Expr; 
 + 
 +    // tree.Variables: Dictionary<string, object> 
 +    if (!tree.Variables.ContainsKey(name)) 
 +        tree.Variables.Add(name, value); 
 +    else 
 +        tree.Variables[name] value; 
 + 
 +    return null
 +}; 
 + 
 +WhileStmt -> WHILE CondExpr DO StmtList END 
 +
 +    while (Convert.ToInt32($CondExpr) != 0)
     {     {
-        return Convert.ToInt32($NUMBER.ToString());+        $StmtList;
     }     }
-    else if ($STRING != null)+    return null; 
 +}; 
 + 
 +IfStmt -> IF CondExpr DO StmtList (ELSE StmtList)? END 
 +
 +    if (Convert.ToInt32($CondExpr) != 0) 
 +        $StmtList[0]; 
 +    else
     {     {
-        string s = $STRING.ToString(); +        if ($StmtList[1] !null
-        if (s.Length >= 2 && s[0] == '"' && s[s.Length - 1] == '"'+            $StmtList[1];
-            s = s.Substring(1, s.Length - 2); +
-        return s;+
     }     }
-    else if ($IDENT != null)+    return null; 
 +}; 
 + 
 + 
 +// ---------------- Bedingungen / Vergleiche ---------------- 
 +// Ergebnis: int (true=1, false=0) 
 +CondExpr -> AddExpr (RELOP AddExpr)? 
 +
 +    object left = $AddExpr[0]; 
 + 
 +    // ohne Vergleich: truthy 
 +    if ($RELOP == null)
     {     {
-        // Variable lesen +        if (left == null) return 0
-        object v+        if (left is intreturn ((int)left != 0) ? 1 : 0
-        string name = $IDENT.ToString(); +        if (left is bool) return ((bool)left? 1 : 0; 
-        if (!Variables.TryGetValue(name, out v)) +        if (left is string) return (((string)left).Length != 0? 1 : 0
-            throw new Exception("Variable '" + name + "' ist nicht definiert."); +        return 1;
-        return name;+
     }     }
-    else+ 
 +    object right = $AddExpr[1]; 
 +    string op = $RELOP.ToString(); 
 + 
 +    // int vs int 
 +    if (left is int && right is int)
     {     {
-        // Ausdruck +        int l = (int)left; 
-        return $AddExpr;+        int r = (int)right; 
 + 
 +        bool res = 
 +            (op == "<"  && l <  r) || 
 +            (op == "<=" && l <= r) || 
 +            (op == ">"  && l >  r) || 
 +            (op == ">=" && l >= r) || 
 +            (op == "==" && l == r) || 
 +            (op == "!=" && l != r); 
 + 
 +        return res ? 1 : 0;
     }     }
 +
 +    // string vs string (ordinal)
 +    if (left is string && right is string)
 +    {
 +        int cmp = string.CompareOrdinal((string)left, (string)right);
 +
 +        bool res =
 +            (op == "<"  && cmp <  0) ||
 +            (op == "<=" && cmp <= 0) ||
 +            (op == ">"  && cmp >  0) ||
 +            (op == ">=" && cmp >= 0) ||
 +            (op == "==" && cmp == 0) ||
 +            (op == "!=" && cmp != 0);
 +
 +        return res ? 1 : 0;
 +    }
 +
 +    // gemischte Typen: == / != ok, Ordnung nicht
 +    if (op == "==") return 0;
 +    if (op == "!=") return 1;
 +
 +    throw new Exception(
 +        "Invalid comparison between '" +
 +        (left == null ? "null" : left.GetType().Name) +
 +        "' and '" +
 +        (right == null ? "null" : right.GetType().Name) +
 +        "' using '" + op + "'."
 +    );
 }; };
 +
 +
 +// ---------------- Ausdrücke ----------------
 +
 +Expr -> AddExpr
 +{
 +    return $AddExpr;
 +};
 +
 +AddExpr -> MultExpr (PLUSMINUS MultExpr)*
 +{
 +    object value = $MultExpr;
 +    int i = 1;
 +
 +    while ($MultExpr[i] != null)
 +    {
 +        string sign = $PLUSMINUS[i-1].ToString();
 +        object rhs = $MultExpr[i++];
 +
 +        if (sign == "+")
 +        {
 +            // concat wenn einer string ist
 +            if (value is string || rhs is string)
 +            {
 +                string ls = (value == null) ? "" : value.ToString();
 +                string rs = (rhs   == null) ? "" : rhs.ToString();
 +                value = ls + rs;
 +            }
 +            else
 +            {
 +                // beide müssen int sein
 +                if (!(value is int) || !(rhs is int))
 +                    throw new Exception("Operator '+' erwartet Zahl+Zahl oder String-Konkatenation.");
 +                value = (int)value + (int)rhs;
 +            }
 +        }
 +        else
 +        {
 +            // '-' nur numerisch
 +            if (!(value is int) || !(rhs is int))
 +                throw new Exception("Operator '-' ist nur für Zahlen erlaubt.");
 +            value = (int)value - (int)rhs;
 +        }
 +    }
 +
 +    return value;
 +};
 +
 +MultExpr -> Atom (MULTDIV Atom)*
 +{
 +    object accObj = $Atom;
 +
 +    // Wenn kein * oder / folgt, dürfen wir int ODER string einfach durchreichen
 +    if ($Atom[1] == null)
 +        return accObj;
 +
 +    // Sobald * oder / vorkommt: nur Zahlen erlaubt
 +    if (!(accObj is int))
 +        throw new Exception("Operator '*' und '/' sind nur für Zahlen erlaubt.");
 +
 +    int acc = (int)accObj;
 +    int i = 1;
 +
 +    while ($Atom[i] != null)
 +    {
 +        string sign = $MULTDIV[i-1].ToString();
 +        object rhsObj = $Atom[i++];
 +
 +        if (!(rhsObj is int))
 +            throw new Exception("Operator '*' und '/' sind nur für Zahlen erlaubt.");
 +
 +        int rhs = (int)rhsObj;
 +
 +        if (sign == "*")
 +            acc *= rhs;
 +        else
 +            acc /= rhs;
 +    }
 +
 +    return acc;
 +};
 +
 +Atom -> NUMBER | STRING | IDENT | BROPEN Expr BRCLOSE
 +{
 +    if ($NUMBER != null)
 +        return Convert.ToInt32($NUMBER.ToString());
 +
 +    if ($STRING != null)
 +    {
 +        string raw = $STRING.ToString();
 +        raw = raw.Substring(1, raw.Length - 2);
 +
 +        System.Text.StringBuilder sb = new System.Text.StringBuilder();
 +        for (int j = 0; j < raw.Length; j++)
 +        {
 +            char c = raw[j];
 +            if (c == '\\' && j + 1 < raw.Length)
 +            {
 +                char n = raw[++j];
 +                if      (n == 'n') sb.Append('\n');
 +                else if (n == 't') sb.Append('\t');
 +                else if (n == 'r') sb.Append('\r');
 +                else if (n == '\\') sb.Append('\\');
 +                else if (n == '"') sb.Append('"');
 +                else sb.Append(n);
 +            }
 +            else
 +            {
 +                sb.Append(c);
 +            }
 +        }
 +
 +        return sb.ToString();
 +    }
 +
 +    if ($IDENT != null)
 +    {
 +        string name = $IDENT.ToString();
 +        if (tree.Variables.ContainsKey(name))
 +            return tree.Variables[name];
 +        throw new Exception("Undefined variable: " + name);
 +    }
 +
 +    return $Expr;
 +};
 +</code>
 +
 +<code>
 +let x = "b"
 +
 +switch x do
 +  case "a" do
 +    print "case a"
 +  case "b" do
 +    print "case b"
 +  else
 +    print "default"
 +end
 </code> </code>
tinypg.1765460011.txt.gz · Zuletzt geändert: 2025/12/11 14:33 von jango