drunkVoodoo
Anmeldungsdatum: 17. November 2004
Beiträge: 66
Wohnort: $HOME
|
Da ich persönlich immer noch zum grossen Teil in einem Schlaf-Arbeits-Schlaf-Arbeits-Zyklus gefangen bin (heute abend ist eine nette Ausnahme) habe ich die Veröffentlichung einer neuen Aufgabe ziemlich schleifen lassen. Sorry. Deswegen tu ich euch jetzt richtig was an: Ihre Aufgabe, sollten Sie sie übernehmen, ist es, einen kleinen "Assembler" zu programmieren. Die Anweisungen dieses Assemblers sind nach folgendem Schema strukturiert: <operation> <operand1> <operand2> Es gibt eine Variable in der das Ergebnis der Berechnung gespeichert wird (Akkumulator). Der Assembler sollte folgende Ausdrücke "verstehen" (Erklärung nach dem #):
ADD i1 i2 # Zahl 1 und 2 werden addiert und das Ergebnis im Akkumulator gespeichert
SUB i1 i2 # Zahl i2 wird von i1 abgezogen und das Ergebnis im Akkumulator gespeichert
MUL i1 i2 # Zahl i1 wird mit i2 multipliziert und das Ergebnis im Akkumulator gespeichert
DIV i1 i2 # Zahl i1 wird durch i2 geteilt (ganzzahlig) und das Ergebnis im Akkumulator gespeichert Der Akkumulator ist am anfang jedes "Programms" 0. Der Operand "A" wird immer durch den Inhalt des Akkumulators ersetzt. Eine Beispielaufgabe ist z.B.: Akkumulator ist 0.
ADD A 3 Akkumulator ist 3.
MUL 2 4 Akkumulator ist 8.
SUB 14 A Akkumulator ist 6.
MUL A A Akkumulator ist 36.
Das ist eine Aufgabe zum warmwerden. Lösungen dürfen ab Sonntag den 17.4. 20:00 Uhr gepostet werden. Diese Aufgabe ist grundlegend für die Sachen, die ich noch mit euch vorhabe, wer also in Zukunft mitmachen will, sollte jetzt einsteigen. Alle Programmiersprachen, die unter Ubuntu installierbar sind sind erlaubt. Habt Spass! Update: Die Anweisungen sollen von der Standardeingabe gelesen werden, der finale Akkumulatorstand wird auf der Standardausgabe ausgegeben. Dank an Dr_jekyll für die Nachfrage.
|
Apollon
Anmeldungsdatum: 27. Oktober 2004
Beiträge: 724
Wohnort: Darmstadt
|
Ok. Hier meine Lösung. Quick and dirty. Kein AST, kein Evaluator, kein richtiger Tokeniser und noch nicht einmal pures C++ aber es funktioniert. /*---------------------------------------------------------------------------
Filename: asm_interpreter.cpp
Description: Primitiver ASM-Interpreter mit sehr penibler Syntax.
Syntax: operation <operand1> <operand2>
Operation ::= ADD | SUB | MUL | DIV
Operand ::= n R (beliebige rationale Zahl)
die jeweiligen Bausteine dürfen nur durch EIN LEERZEICHEN
getrennt werden.
---------------------------------------------------------------------------*/
#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;
int main(int argc, char *argv[])
{
double akku = 0;
double operand1 = 0;
double operand2 = 0;
for (;;) {
string input = "";
string operation = "";
string op1 = "";
string op2 = "";
getline(cin, input);
if (input == "quit") {
break;
}
operation.push_back(input[0]);
operation.push_back(input[1]);
operation.push_back(input[2]);
for (int i = 4; i < input.length(); i++) {
if (input[i] != ' ') {
op1.push_back(input[i]);
} else {
input.erase(0, i++);
op2 = input;
break;
}
}
if (op1 == "A") {
operand1 = akku;
} else {
operand1 = atof(op1.c_str());
}
if (op2 == "A") {
operand2 = akku;
} else {
operand2 = atof(op2.c_str());
}
if (operation == "ADD") {
akku = operand1 + operand2;
} else if (operation == "MUL") {
akku = operand1 * operand2;
} else if (operation == "DIV") {
akku = operand1 / operand2;
} else if (operation == "SUB") {
akku = operand1 - operand2;
} else {
cerr << "Unknown operation.\n";
}
cout << operation << " " << op1 << op2 << endl;
cout << "Akkumulator state: " << akku << endl;
}
return 0;
} Ich weiss. Da fehlen Kommentare.
|
blackbird
Anmeldungsdatum: 19. November 2004
Beiträge: 3396
Wohnort: Hermagor, Kärnten - Österreich
|
Bei mir auch keine Kommentare, aber der Quelltext ist sowieso selbsterklärend:
#!/usr/bin/env python
# -*- coding utf-8 -*-
"""
PSEUDO ASM INTERPRETER
Syntax:
ADD i1 i2
SUB i1 i2
MUL i1 i2
DIV i1 i2
"""
from sys import stdin, stdout, stderr
from __future__ import division
class interpreter:
def __init__(self):
"Initialisiert den Interpreter"
self.A = 0
def calc(self):
"Berechtet die gespeicherte Rechnung"
lines = self.data.splitlines()
l = 0
for line in lines:
l += 1
if line.strip() != "":
try:
token = line.split(" ", 3)
for i in range(0, len(token)):
token[i] = token[i].strip()
if token[1] == "A": token[1] = self.A
if token[2] == "A": token[2] = self.A
token[1] = int(token[1])
token[2] = int(token[2])
if token[0] == "ADD":
self.A = token[1] + token[2]
if token[0] == "SUB":
self.A = token[1] - token[2]
if token[0] == "MUL":
self.A = token[1] * token[2]
if token[0] == "DIV":
self.A = token[1] // token[2]
except:
stderr.write(" !Syntaxfehler, Zeile %s\n" % l)
self.A = -1
if __name__ == "__main__":
i = interpreter()
i.data = stdin.read()
i.calc()
stdout.write(str(i.A)+"\n") Wiedermal Python, Liest von stdin, also auch von pipe und gibt bei Synaxfehler eine kleine Meldung aus.
|
bitbieger
Anmeldungsdatum: 24. Januar 2005
Beiträge: 85
Wohnort: NRW
|
c++...extrem quick'n'dirty: #include <iostream>
#include <map>
#include <string>
using namespace std;
typedef double (*calcPtr)(double, double);
typedef map<string, calcPtr> op_map;
double calcADD(double a, double b) { return a+b; }
double calcSUB(double a, double b) { return a-b; }
double calcMUL(double a, double b) { return a*b; }
double calcDIV(double a, double b) { return a/b; }
double accuSubst(const string& val, double accu)
{
return (*val.c_str() == 'A') ? accu : atof(val.c_str());
}
int main(int argc, char* argv[])
{
op_map ops;
ops["ADD"]=calcADD;
ops["SUB"]=calcSUB;
ops["MUL"]=calcMUL;
ops["DIV"]=calcDIV;
string a, b, op;
double accu = 0.0;
while(!cin.eof()) {
cin >> op >> a >> b;
if (!cin.fail() && ops[op])
accu = ops[op](accuSubst(a, accu), accuSubst(b, accu));
}
cout << accu << endl;
return 0;
}
|
blackbird
Anmeldungsdatum: 19. November 2004
Beiträge: 3396
Wohnort: Hermagor, Kärnten - Österreich
|
Nur 3 Leute? Da geht noch mehr 😛
|
Freeze2006
Anmeldungsdatum: 6. März 2005
Beiträge: 210
Wohnort: Rolfshagen
|
hm...also ich hab die aufgabe erst heute verstanden, weil ich vorher den sinn nicht ganz gesehen habe, nen taschenrechner zu bauen, aber naja... so zu mir, ich habe kaum programmier erfahrung, erst knapp 1 1/2 jahre schulinformatik, aber mit hilfe eines schlauen buches hab ich mich heute an meiner ersten klasse versucht O_o ⇒ C++ das ergebnis:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
class accu
{
public:
accu(string s_operator, string s_op1, string s_op2, double v_accum);
void calc();
void display();
double getAkkum(){ return n_accum;}
accu::~accu(){}
private:
double n_accum;
double op1;
double op2;
string private_operator;
};
accu::accu(string s_operator, string s_op1, string s_op2, double v_accum)
{
if(s_op1!="A") //Bei bedarf vorherigen Akkumulator
{
std::istringstream inStream(s_op1);
inStream >> op1;
}
else op1=v_accum;
if(s_op2!="A") //Bei bedarf vorherigen Akkumulator
{
std::istringstream inStream(s_op2);
inStream >> op2;
}
else op2=v_accum;
private_operator=s_operator;
}
void accu::calc() //Der eigentliche Rechner
{
if(private_operator=="ADD") n_accum = op1 + op2;
if(private_operator=="SUB") n_accum = op1 - op2;
if(private_operator=="MUL") n_accum = op1 * op2;
if(private_operator=="DIV") n_accum = op1 / op2;
}
void accu::display() //Ausgabe O_o
{
cout << "\nAkkumulator ist: " << n_accum;
}
int main()
{
string operation, op1, op2;
double akku=0.0;
do
{
cout << "\nOperation | a | b\n"; //Einlesen
cin >> operation >> op1 >> op2;
accu nr1(operation, op1, op2, akku); //Anlegen
nr1.calc();
nr1.display();
akku=nr1.getAkkum(); //für die nächste operation Akkumulator stand holen
}while(operation != "exit");
return 0;
} wie bei den anderen auch mit leerzeichen trennen.... P.S.: bin für verbesserungen immer zu haben!!
|
bitbieger
Anmeldungsdatum: 24. Januar 2005
Beiträge: 85
Wohnort: NRW
|
Ich hab für die Puristen noch eins in plain C gemacht: #include <stdio.h>
#include <stdlib.h>
int main(void)
{
char d[3][12]; double a = 0.0, b, c;
while(3 == scanf("%s %s %s",d[0],d[1],d[2])) {
a=(b=*d[1]>'9'?a:atof(d[1]),c=*d[2]>'9'?a:atof(d[2]),*d[0]=='A'?b+c:*d[0]=='S'?b-c:*d[0]=='M'?b*c:b/c);
}
printf("%g\n",a);
return 0;
} Syntax muss korrekt sein. OPs können abgekürzt werden MUL=M, ADD=A, etc. Zahlen dürfen maximal 11-Stellig sein, sonst knallts... Ich denke darüber nach, es patentieren zu lassen! 😉 have fun, der bitbieger
|
blackbird
Anmeldungsdatum: 19. November 2004
Beiträge: 3396
Wohnort: Hermagor, Kärnten - Österreich
|
Hier noch eine Version von mir, ohne Fehlerbehandlung und so einen Käse:
#!/usr/bin/env python
import sys
data = sys.stdin.read().splitlines(); a = 0
for line in data:
m, n1, n2 = line.split(' ', 3); n1 = int(n1); n2 = int(n2);
if n1 == 'A': n1 = a
if n2 == 'A': n2 = a
if m == "MUL": a = n1 * n2
if m == "DIV": a = int(n1 / n2)
if m == "ADD": a = n1 + n2
if m == "SUB": a = n1 - n2
print a
|
bitbieger
Anmeldungsdatum: 24. Januar 2005
Beiträge: 85
Wohnort: NRW
|
Ich warte noch auf den berühmten Einzeiler in Perl... ☺
|
blackbird
Anmeldungsdatum: 19. November 2004
Beiträge: 3396
Wohnort: Hermagor, Kärnten - Österreich
|
bitbieger hat geschrieben: Ich warte noch auf den berühmten Einzeiler in Perl... ☺
Den hab ich nicht, aber eine Variante in Python mit Sicherheitslücke integriert:
#!/usr/bin/env python
import sys; data = sys.stdin.read().splitlines(); a = 0
for line in data:
num = [e.replace("A", str(a)) for e in line.split(' ', 3)[1:]]
n1, n2 = [int(i) for i in num]
rmap = {"MUL":'n1*n2', "DIV":'int(n1/n2)', "ADD":'n1+n2', "SUB":'n1+n2'}
a = eval(rmap[line[0:3]])
print a
|
sowatt
Anmeldungsdatum: 30. Oktober 2004
Beiträge: 72
Wohnort: Hamburg
|
Also ein Einzeiler ist das nicht gerade aber in Perl. Das kann man sicher besser machen, ich bin aber erst dabei mich mit Perl zu beschäftigen und habe diese Aufgabe natürlich als wilkommenen Test genommen. #!/usr/bin/perl
use strict;
use warnings;
use diagnostics;
my $operation = " ";
my $temp = 0;
my $op1;
my $op2;
my $eingabe = " ";
print "Beenden des Programm's mit Taste q :\n\n";
print "Ein korrekter Ausdruck ist z.B. ADD 3 5(Leerzeichen beachten!).\n";
print "Sie koennen die Operanden auch durch den Buchstaben A ersetzen,\n";
print "was zur Folge hat das der Aktuelle Wert des Akkumulator's genommen wird.\n\n";
while() {
print "Bitte den Ausdruck eingeben :\n";
chomp ($eingabe = <STDIN>);
if ($eingabe ne "q") {
if ($eingabe =~ /^(ADD|SUB|MUL|DIV) (\d+|A{1}) (\d+|A{1})/) {
$eingabe =~ s/ A/ $temp/g;
($operation, $op1, $op2) = split (" ",$eingabe);
if ($operation eq "ADD") {
$temp = $op1 + $op2;
print "A = $temp\n";
}
elsif ($operation eq "SUB") {
$temp = $op1 - $op2;
print "A = $temp\n";
}
elsif ($operation eq "MUL") {
$temp = $op1 * $op2;
print "A = $temp\n";
}
elsif ($operation eq "DIV") {
$temp = $op1 / $op2;
print "A = $temp\n";
}
}else { print "Fehler! Der Ausdruck ist nicht korrekt.\n"; }
}else { last; }
}
print "Der Akkumulator hat den Wert : A = " .int($temp)."\n"; Das die Lösung in C wesentlich kürzer ist als meine in Perl lässt mich doch schon sehr nachdenklich werden... MfG sowatt
|
bitbieger
Anmeldungsdatum: 24. Januar 2005
Beiträge: 85
Wohnort: NRW
|
sowatt hat geschrieben: Das die Lösung in C wesentlich kürzer ist als meine in Perl lässt mich doch schon sehr nachdenklich werden...
Dafür kann man deine Version viel besser lesen... \^^
#!/usr/bin/perl -w
$A=0.0;
%op=(ADD=>sub{$A=$2+$3;}, SUB=>sub{$A=$2-$3;}, MUL=>sub{$A=$2*$3;}, DIV=>sub{$A=$2/$3;});
while(<>) {
s/\sA/ $A/g;
/(ADD|SUB|MUL|DIV) ([\d.]+) ([\d.]+)/ && $op{$1}->();
}
print "$A\n";
|
sowatt
Anmeldungsdatum: 30. Oktober 2004
Beiträge: 72
Wohnort: Hamburg
|
Stimmt. Das sieht ja echt "böse" aus, was Du da hingezaubert hast. 😉 Das zeigt mir das ich noch eine Menge vor mir habe um Perl zu lernen. MfG sowatt
|
bitbieger
Anmeldungsdatum: 24. Januar 2005
Beiträge: 85
Wohnort: NRW
|
Das hat nichts damit zu tun Perl zu können, sondern ausschließlich damit, Source Code zu verunstalten ☺ (Ich kann nämlich gar kein Perl...)
|
drunkVoodoo
(Themenstarter)
Anmeldungsdatum: 17. November 2004
Beiträge: 66
Wohnort: $HOME
|
Schön, dass sich diese Aufgabe doch so entwickelt hat ... ich selbst hatte vor, det Janze in Lua zu realisieren (gibt einen Anlass dafür), bin aber bis jetzt noch nicht ganz hinterhergekommen. Warum? Weil ich im Gegensatz zu euch weiss, dass die nächste und übernächste "Aufgabe" auf dieser aufbauen werden. Wird lustig. Glaube ich. Werde Freitag oder Samstag wieder hier vorstellig werden und einen neuen (Programmier-)Knochen in die Runde werfen.
|