Programmiersprachen Flashcards
Programmierebenen in aktuellen Rechnern
Rechner als Hierarchie von Sprachebenen, deren Sprachen
- durch Übersetzung ineinander überführbar bzw.
- durch Interpretierung direkt ausführbar sind
Hardware → Sprache L1 → … → Sprache Ln-1 → Sprache Ln auf Benutzerebene

Höhere Programmiersprachen
- zur Formulierung von Programmen aus einem bestimmten Anwendungsbereich
- unabhängig von Hardware der Rechenmaschinen → keine umkehrbare eindeutige Zuordnung ihrer Konstrukte zu konkreten Maschinenbefehlen notwendig
- orientiert an einem Bedeutungsfeld (Semantik) und an einem bestimmten Problemfeld
- Beschreibung der Sprache durch: Syntax (Aufbauregeln) und Semantik (Bedeutung der Sprachkonstrukte)
- Übersetzung o. Interpretierung der Sprache in Maschinenprogramme notwendig
Maschinensprache
- Darstellung der Befehle in numerischer Binärcodierung
- semantisch niedrigste Ebene der Programmierung einer CPU
- durch CPU direkt ausführbare Befehle
2 Möglichkeiten der Ausführung:
- interaktiv durch Mikroprogramme
- direkt durch Hardwarezugriff
Mikroprogrammierung
= Firmware
- numerische Binärcodierung
- Ausführung von Maschinenbefehlen durch Folge von Mikrobefehlen
- einfachste Ablaufsteuerungen
- Bewegung von Daten
- Öffnen von Gattern
- Tests (z.B. ob Transistoren funktionieren)
- in modernen Rechnern läuft Steuerung fas ausschließlich durch Mikroprogrammeinheiten (schneller/flexibler/übersichtlicher als feste Verdrahtung)
- Sprache, mit der Prozessoren im Chip-Design entwickelt werden
Mikroprogrammierung
Aufgaben der Steuereinheit
FETCH: Holen von Befehlen → Befehle addressieren und laden
DECODE: Entschlüsseln von Befehlen → Zerlegung in Bestandteile (Operations-, Operandenteil) und Erkennen der Befelsart
EXECUTE: Initiieren der Befehlsausführung → Versorgung der an der Befehlsausführung beteiligten Funktionseinheiten mit den notwendigen Steuersignalen
→ Pipelining: wenn 1. Befehl decodiert wird, kann 2. schon geholt werden = 3x schneller → z.B. paralleles Arbeiten bei Graphikkarten

Mikroprogrammierung
Steuerung des physischen Ablaufs innerhalb eines Rechners
- duech Setzen von Steuersignalen
- bewirken Öffnen von “Türen” in den Datenwegen
- Durchschalten der Datenwege
- Auslösung elementarer Operationen

z.B. Registerinhalt wird auf Bus gelegt, falls s=1 (wahr) anliegt, bei s=0 wird kein Signal an Bus weitergeleitet
Maschinensprachen
Eigenschaften
Instruktionssatz/Maschinensprache: Menge aller Maschinenbefehle einer CPU - niedrigste für die Programmierung frei zugängliche Ebene
Maschinenbefehl: binäres Wort fester Länge zur Auslösung einer elementaren Operation einer CPU
Maschinenprogramm: Folge von Maschinenbefehlen, Ablage im Hauptspeicher eines Rechners
Maschinensprachen
Aufbau von Maschinenbefehlen
Operationscode (OpCode): Angabe der auszuführenden Operation
Operandenadressen (OpAdr): Spezifikation der Operanden, auf die die Operation angewendet werden soll, durch Angabe von
- Konstanten
- Registeradressen
- Hauptspeicheradressen
Maschinensprache
Typische Befehlsformate
maximale Anzahl der OpAdr eines Befehls abhängig vom betrachteten Rechner und Art des Befehls - Beispiel c = a + b

1-Adress-Maschine: spezifierter Operand wird mit Inhalt eines ausgezeichneten Registers (“Accumulator”=Zwischenspeicher” gemäß dem OpCode verknüft, Ergebnis in Akkumulator gespeichert
3 Befehle, aber schnell: laod a → add b → store c
2-Adress-Maschine: Ergebnis wird im 2. Operanden gespeichert
store a,c → add b,c
3-Adress-Maschine: spezielles Ergebnisregister add a,b,c
Maschinensprache
Befehlsarten einer CPU
- Datentransportbefehle: Kopieren von Inhalten von Registern/Hauptspeicherzellen (load,store)
- Arithmetische und logische Befehle: arithemtische/logische Verknüpfung o. Schiebeoperation, angewendet auf Inhalte von Registern/Hauptspeicherzellen (add)
- Ablaufsteuerungsbefehle: Unterbrechung des sequentiellen Programmablaufs durch Sprungbefehle (if, jump, Schleifen)
- Ein-/Ausgangsbefehle: Kommunikation mit E/A-Geräten
- Sonderbefehle: Interruptbehandlung, Anhalten/Zurücksetzen der CPU, …
Maschinensprache
Beispiel im 1-Adress-Format
- 16 Bit Befehlslänge
- Operationscode: 4 Bit → 24 Befehle
- Operandenadresse: 12 Bit zur SPezifizierung einer Hauptspeicheradresse
- Akkumulator: Register A
- zur besseren Lesbarkeit: OpCode symbolisch statt numerisch
- nur absolute Adressierung, 16-Bit-Ganzzahlen

Komplexere Maschinensprachen
Konzepte zur Steigerung der Leistungsfähigkeit und des Anwendungskomforts:
-
Realisierung der Stapelverarbeitung, z.B. für
- Abarbeitung arithmetischer Ausdrücke
- Verwaltung geschachtelter Prozeduraufgaben
- Rechnen mit GPZ, möglichst mit großen Wortlängen
- verschiedene Adressierungsarten
Maschinensprache
Adressierungsarten

Assemblersprache
Eigenschaften
- maschinenorientierte Pogrammiersprache zur Formulierung von Programmen, die sich an den Eigenarten eines bestimmten Rechners orientierten → hardwarenahes Programmieren
- ähnliche Strukturen wie Maschinensprache, aber mehr Komfort
- in Maschinenprogramme übersetzt → keine direkte Ausführung durch Interpreter
- Assembler/Assemblierer zur Übersetzung
- Befehle werden symbolisch statt numerisch notiert
- jeder Operationscode hat festen symbolischen Namen (“mnemonisch”), der an Semantik der Operation erinnert, z.B. ADD für Addition
- Operandenadressen können Namen zugeordnet werden → Adressierung über diesen Namen
- Befehl (ihre Adressen) können durch Lebel gekennzeichnet werde (etwa zur Festlegung von Sprungzielen)
- Unterschied zu Maschinensprache: zusätzliche Pseudobefehle — nur für den Assembler verständliche Anweisungen für die Steuerung der Übersetzung von Assemblerprogrammen
- Reservierung von Speicherplatz für Variablen
- Festlegung von Programmanfangsadresse
- Zuweisung von Werten/Adressen an symbolische Namen (Variablenzuweisung)
Assemblersprache
Befehlsaufbau
Markenfeld: zur symbolischen Kennzeichnung eines Assemblerbefehls, entspricht auf Maschinenebene einer Befehlsadresse
Operationsfeld: enthält entweder mnemonic eines Maschinenbefehls o. Teil eines Pseudobefehls
Operandenfeld: enthält einen/mehrere/keinen Operanden, d.h. Konstanten o. Adressangaben
Kommentarfeld: (optional) zur Dokumentation der Befehle, kann alle möglichen Zeichen enthalten

Höhere Programmiersprachen
Kategorisierung
- prozedurale Programmiersprachen: ADA, BASIC, PASCAL, C, FORTRAN
- funktionale Programmiersprachen: LISP, LOGO, Gofer
- prädikative Programmiersprachen: PROLOG, im Bereich der KI
- objektorientierte Programmiersprachen: C++, C#, Java, Selphi, Smalltalk
Assemblersprache
Assemblierer - Aufgaben
Programm zur Übersetzung von Assemblerprogrammen in ausführbare Maschinenprogramme
- Syntaxanalyse der Befehle
- Ausführung der Pseudobefehle
- Konvertieren von Konstanten in Binärdarstellung
- Generierung des Maschinencodes für den Operationsteil
- Berechnung von Adressenn, die durch Symbole oder Ausdrücke gegeben sind
- Adressrechnung: absolut o. relativ zum Programmanfang
Assemblersprache
Assembler - 2-Pass-Assembler
einmaliges Durchlaufen beim Übersetzen genügt nicht, da Adressen von Vorwärtssprüngen nicht bekannt sind
- Durchlauf (Pass 1): Aufbau der Symboltabelle: alle verwendeten Namen/MArken mit ihrer Adresse und evtl. weiteren Angaben in Datei gespeichert
- Durchlauf (Pass 2): EInsetzen der Adresswerte für die Symbole mit Hilfe der Symboltabelle im übersetzten Programm

Interpreter
Vorgehen: nacheinander Analyse jeder Anweisung mit unmittelbarer Ausführung
-
Vorteile: insbesondere bei Programmentwicklung
- Änderungen im Quellprogramm direkt ausführbar
- Werte von Variablen bei Ausführung meist abfragbar –> vereinfachte Fehlererkennung
-
Nachteile:
- relativ großer Zeitaufwand beim Interpretieren (z.B. Schleifen immer neu interpretiert)
- Adressen sind bei jedem Durchlauf neu zu berechnen

Compiler
Vorgehen: alle Anweisungen werden zuerst in Maschinensprache o. Assembler übersetzt, das übersetzte Programm gespeichert und ist dann ausführbar
- Vorteil: erzeugtes Programm kann beliebig oft ausgeführt werden, ohne dass eine erneute Übersetzung notwendig ist; Quelltext ist geschützt
- Nachteil: Fehlererkennung und Programmtest schwieriger als bei interpretativer Ausführung

Compiler
4 Phasen des Kompilierens
- lexikalische Analyse (“Scanner”)
- syntaktische Analyse (“Parsing”)
- semantische Analyse und Codegenerierung
- Codeoptimierung

Compiler
- Phase: lexikalische Analyse (“Scanner”)
Zerlegung des gesamten Programms in eine Folge kleinster syntaktischer Einheiten (Tokens) anhand von Trennzeichen
-
Tokens:
- benutzerdefinierte Namen, werden in Tabelle eingetragen (für Variablen o. Datentypen)
- Grundsymbole: Wortsymbole und feste syntaktische Einheiten (BEGIN, IF, :=, …)
- Zahlen: Konvertierung verschiedener Darstellungen in rechnerinterne Darstellung
- Kommentare: werden überlesen

Compiler
- Phase: syntaktische Analyse (“Parsing”)
- überprüft syntaktische Korrektheit des Programms gemäß den Regeln der kontextfreien Grammatik der Programmiersprache
- erzeugt zugehörigen Ableitungsbaum = parsing tree

Compiler
- Phase: semantische Analyse und Codegenerierung
-
semantische Analyse: überprüft semantische Regeln
- Vereinbarung jedes benutzten Namens
- Verträglichkeit von Typen innerhalb eines logischen o. arithmetischen Ausdrucks o. in Zuweisungen
-
Codegenerierung:
- Durchlaufen des Syntaxbaumes mit gleichzeitiger Erzeugung des Assembler-/Maschinenprogramms
- i.d.R. ist jedem nichhterminalen Symbol eine Prozedur zugeorndnet, die den Code für dieses Symbol erzeugt
Compiler
- Phase: Codeoptimierung
Optimierung des erzeugten Programms
insbesondere:
- Laufzeitoptimierung
- Speicherplatzoptimierung
- z.B. Erkennung mehrfach auftretender (arithmetischer) Ausdrücke wie x = f(z)+b und y = f(z)+b*
- Ausdruck wird ersetzt z.B. durch y=x → nur einmalige Auswertung*
Java Virtual Machine
- Java-Code wird zu Bytecode kompiliert
- Befehl javac
- plattformunabhängig, nicht direkt ausführbar
- Bytecode wird von virtueller Maschine interpretiert
- Nachteil: Laufzeit
- Vorteil: Sicherheit (kann ohne Einsicht ins Quellprogramm weitergegeben werden)
-
JIT-Compiler (Just in Time)
- bevor eine Methode das erste Mal benutzt wird, wird der entsprechende Bytecode in Maschinensprache übersetzt
- übersetzte Methoden werden gespeichert, um Mehrfachübersetzungen zu vermeiden
- “echte” Compiler auch verfügbar → keine Plattformunabhängigkeit
