diff --git a/index.html b/index.html new file mode 100644 index 0000000..4b3798e --- /dev/null +++ b/index.html @@ -0,0 +1,298 @@ + + + + + + + + Vorlesungsunterlagen Softwareprojekt + + + + +
+

Vorlesungsunterlagen Softwareprojekt

+

Martin Sulzmann

+
+

Inhalt

+

Übersicht

+ +

Unterlagen auf Deutsch und Englisch als html mit komplettem +Programmcode.

+

Kurz und knapp

+ +

Einführung in C

+

Teil 1

+ +

Teil 2

+ +

Teil 3

+ +

Einführung in C++

+

Teil 1

+

C++ kompakt

+ +

Teil 2

+

Nochmal Zeiger und Resourcen Kontrolle.

+ +

Teil 3

+

Polymorphie

+

Teil 4

+

Funktionaler Programmierstil

+

Teil 5

+

QuickCheck: Automatisiertes Testen

+

Laboraufgaben und Beispiele

+

Aufgabensammlung

+

Weitere Beispiele

+

Scheinaufgaben

+

Übung (Schein)

+

Weitere Themen

+ +

Software Entwicklung

+ +

Referenzen/Literatur

+ +

C++ online tutorials

+ +

C++ reference

+ + + diff --git a/lec-cpp-advanced-vm.html b/lec-cpp-advanced-vm.html new file mode 100644 index 0000000..1824877 --- /dev/null +++ b/lec-cpp-advanced-vm.html @@ -0,0 +1,561 @@ + + + + + + + + + Stack-basierte virtuelle Maschinen in C++ + + + + + +
+

Stack-basierte virtuelle Maschinen in C++

+

+Martin Sulzmann +

+
+
+

Übersicht

+

Betrachte Kompilierung von Programmen

+
Quellcode  ==> Syntaxbaum ==> .... ==> Assembler/Maschinencode
+

Assembler/Maschinencode: Intel? ARM? …

+

Ziel:

+ +

Hier: Stack-basierte virtuelle Maschine (VM) (auch Stack machine +genannt).

+ +
+
+

Stack-basierte VM

+

Instruktionen

+

Folgende Instruktionen sind vorhanden.

+

Push i

+ +

Plus

+ +

Mult

+ +

Beispiel 1

+
Push 1; Push 2; Plus;
+

Ausführung ist wie folgt.

+

Den Stack schreiben wir von links nach rechts (d.h. links steht das +oberste Element).

+
Initial:
+
+Push 1; Push 2, Plus
+
+Stack = []
+
+
+1. Schritt
+
+Push 2, Plus
+
+Stack = [1]
+
+2. Schritt
+
+Plus
+
+Stack = [2, 1]
+
+3. Schritt
+
+
+Stack = [3]
+

Beispiel 2

+
Push 1; Push 2; Push 3; Plus; Mult;
+

Ausführung ist wie folgt.

+
Initial:
+
+Push 1; Push 2; Push 3; Plus; Mult;
+
+Stack = []
+
+1. Schritt
+
+Push 2; Push 3; Plus; Mult;
+
+Stack = [1]
+
+2. Schritt
+
+Push 3; Plus; Mult;
+
+Stack = [2, 1]
+
+3. Schritt
+
+Plus; Mult;
+
+Stack = [3, 2, 1]
+
+4. Schritt
+
+Mult;
+
+Stack = [5, 1]
+
+5. Schritt
+
+Stack = [5]
+
+
+

Arithmetische Ausdrücke

+

Betrachte

+
1 + 2
+

Obiger Ausdruck kann wie folgt dargestellt werde

+
Push 1; Push 2; Plus;
+

Für arithmetische Ausdrücke verwenden wir “infix” Notation:

+ +

Im Fall von VM Instrukionen verwenden wir “postfix” Notation:

+ +

Diese Darstellung von arithmetischen Ausdrücken ist auch bekannt als +Reverse +Polish Notation (RPN).

+

Was ist der Vorteil von RPN?

+ +

Betrachte

+
1 * (2 + 3)
+

dargestellt als

+
Push 1; Push 2; Push 3; Plus; Mult;
+
+
+

Von arithmetischen Ausdrücken zu VM Instruktionen

+

Wir zeigen wie wir systematisch Ausdrücke als VM Instruktionen +darstellen können.

+

Wr nehmen einen vereinfachten Befehlssatz an.

+ +

Z.B.

+
1 * (2 + 1)
+

entspricht dann

+
ONE; TWO; ONE; PLUS; MULT
+

Schritt 1: Darstellung als +Syntaxbaum

+
1 * (2 + 1)
+

entspricht dann

+
Mult(Int(1), Plus(Int(2), Int(1)))
+

Schritt +2: Konvertiere Syntaxbaum in eine Sequenz von VM Instrukionen

+

Idee: Rekursiver Ansatz (von “innen” nach “aussen”).

+
  Mult(Int(1), Plus(Int(2), Int(1)))
+
+==convert=>
+
+   Zwischenschritte:
+
+      Int(1) ==convert=>  ONE
+
+
+      Plus(Int(2), Int(1)) ==convert==>  ONE; TWO; PLUS
+
+
+   Fasse Zwischenergebnisse zusammen:
+
+
+    ONE; TWO; ONE; PLUS; MULT
+

Wir implementieren das ganze in C++ und

+ +
+
+

Einfache Stack Maschine in C++

+

+// Simple stack-based VM.
+
+#include <vector>
+#include <stack>
+#include <iostream>
+#include <string>
+#include <memory>
+using namespace std;
+
+
+///////////////////////////////////////
+// VM code
+typedef enum {
+  PLUS,
+  MULT,
+  ONE,
+  TWO
+} Code_t;
+
+string show(Code_t c) {
+  switch(c) {
+  case ONE: return "1";
+  case TWO: return "2";
+  case PLUS: return "+";
+  case MULT: return "*";
+  }
+}
+
+string show(vector<Code_t> cs) {
+  string s;
+  for(int i=0; i < cs.size(); i++) {
+    s = s + show(cs[i]);
+    if(i < cs.size() - 1) {
+      s = s + " ";
+    }
+  }
+  return s;
+}
+
+///////////////////////////////////////
+// Expressions
+//  - eval (interpreter)
+//  - convert to "reverse polish notation"
+//        Operands come first
+//        Computations require a single stack
+class Exp {
+public:
+  virtual int eval() = 0;
+  virtual vector<Code_t>convert() = 0;
+};
+class IntExp : public Exp {
+public:
+  int x;
+  IntExp(int x) {
+    if(x == 1 || x == 2) {
+      this->x = x;
+    }
+    else {
+      this->x = 1;
+      cout << "\nmust be 1 or 2";
+    }
+  }
+  int eval() { return this->x; }
+  vector<Code_t>convert() {
+    vector<Code_t> v;
+    auto n = x == 1 ? ONE : TWO;
+    v.push_back(n);
+
+    return v;
+  }
+};
+class PlusExp : public Exp {
+public:
+  std::shared_ptr<Exp> left, right;
+  PlusExp(std::shared_ptr<Exp> left, std::shared_ptr<Exp> right) {
+    this->left = left; this->right = right;
+  }
+  int eval() { return left->eval() + right->eval(); }
+  vector<Code_t>convert() {
+    auto v1 = left->convert();
+    auto v2 = right->convert();
+    v1.insert(v1.end(),v2.begin(),v2.end()); // append v2 to v1
+    v1.push_back(PLUS);
+
+    return v1;
+  }
+};
+
+class MultExp : public Exp {
+public:
+  std::shared_ptr<Exp> left, right;
+  MultExp(std::shared_ptr<Exp> left, std::shared_ptr<Exp>right) {
+    this->left = left; this->right = right;
+  }
+  int eval() { return left->eval() * right->eval(); }
+  vector<Code_t>convert() {
+    auto v1 = left->convert();
+    auto v2 = right->convert();
+    v1.insert(v1.end(),v2.begin(),v2.end()); // append v2 to v1
+    v1.push_back(MULT);
+
+    return v1;
+  }
+};
+
+// Helper functions
+
+std::shared_ptr<Exp> newInt(int i) {
+  return std::make_shared<IntExp>(i);
+}
+
+std::shared_ptr<Exp> newPlus(std::shared_ptr<Exp> left, std::shared_ptr<Exp> right) {
+  return std::make_shared<PlusExp>(PlusExp(left,right));
+}
+
+std::shared_ptr<Exp> newMult(std::shared_ptr<Exp> left, std::shared_ptr<Exp> right) {
+  return std::make_shared<MultExp>(MultExp(left,right));
+}
+
+
+///////////////////////////////////////
+// VM run-time
+class VM {
+    vector<Code_t> code;
+  public:
+    VM(vector<Code_t> c) : code(c) {}
+
+  void showRunConvert() {
+    cout << "\n VM code: " << show(code);
+    cout << "\n => " << run();
+    cout << "\n Exp: " << convert()->eval();
+  }
+
+  int run() {
+    stack<int> s;
+
+    for(int i = 0; i < code.size(); i++) {
+    switch(code[i]) {
+    case ONE:
+      s.push(1);
+        break;
+    case TWO:
+      s.push(2);
+        break;
+    case MULT: {
+      auto right = s.top();
+      s.pop();
+      auto left = s.top();
+      s.pop();
+      s.push(left * right);
+      break;
+    }
+    case PLUS: {
+      auto right = s.top();
+      s.pop();
+      auto left = s.top();
+      s.pop();
+      s.push(left + right);
+      break;
+    }
+    } // switch
+      } // for
+
+      return s.top();
+  } // run
+
+  std::shared_ptr<Exp> convert() {
+    stack<std::shared_ptr<Exp>> s;
+
+      for(int i = 0; i < code.size(); i++) {
+    switch(code[i]) {
+    case ONE:
+      s.push(newInt(1));
+        break;
+    case TWO:
+      s.push(newInt(2));
+        break;
+    case MULT: {
+      auto right = s.top();
+      s.pop();
+      auto left = s.top();
+      s.pop();
+      s.push(newMult(left,right));
+      break;
+    }
+    case PLUS: {
+      auto right = s.top();
+      s.pop();
+      auto left = s.top();
+      s.pop();
+      s.push(newPlus(left,right));
+      break;
+    }
+    } // switch
+      } // for
+
+      return s.top();
+  } // convert
+
+
+};
+
+
+
+///////////////////////////////////////
+// Examples
+
+void testVM() {
+
+  {
+    vector<Code_t> cs{
+      ONE, TWO, TWO, PLUS, MULT
+    };
+
+
+    VM(cs).showRunConvert();
+  }
+
+  {
+    vector<Code_t> cs{
+      ONE, TWO, PLUS, TWO, MULT
+    };
+
+
+    VM(cs).showRunConvert();
+  }
+
+}
+
+
+void testExp() {
+
+  auto e = newPlus(newMult(newInt(1),newInt(2)), newInt(1));
+
+  auto run = [](std::shared_ptr<Exp> e) {
+        cout << "\n Exp yields " << e->eval();
+        auto vm = VM(e->convert());
+        vm.showRunConvert();
+  };
+
+  run(e);
+
+}
+
+
+int main() {
+
+  testVM();
+
+  // testExp();
+}
+
+
+
+/*
+
+
+
+Wie koennten wir das ganze testen?
+
+z.B.
+
+Property 1:
+
+ Exp => convert => VMCode => convert Exp2
+
+ teste ob Exp.eval == Exp2.eval ist
+
+Property 2:
+
+ VMCode => convert => Exp => convert => VMCode2
+
+ teste ob VMCode.run == VMCod2.run
+
+
+Generierung von Testeingaben!
+Z.B. generiere beliebige Exp Objekte!
+
+
+
+ */
+
+ +