Ein Parser implementiert eine Code-Grammatik.
Für jede Regel wird eine Funktion erstellt.
Ein Parser implementiert eine Code-Grammatik.
Für jede Regel wird eine Funktion erstellt.
class Token_stream {
public:
void set(string line);
Token get();
void put_back(Token t);
private:
istringstream calculation;
bool full = false;
Token buffer;
};
Eine Klasse beinhaltet Klassenvariablen und Klassen-Funktionen.
Instanzierung
Token_stream current_token_stream;
current_token_stream ist eine Instanz dieser Klasse. Alle Funktionen (die gebraucht werden um die Instanz zu verarbeiten) brauchen zuerst den Instanznamen.
current_token_stream.set(calculation_line);
Klassen-Funktionen
Jede Funktion einer Klasse muss nach der Klassendefinition definiert werden. Die Funktion braucht vor ihrem Namen die Klasse, zu der sie gehört.
void Token_stream::put_back(Token t) {
// check if token is already in buffer
if (token_buffer_full) {
throw std::overflow_error("buffer contains already a Token");
}
// set token in buffer
token_buffer = t;
token_buffer_full = true;
}
Funktionen einer Klasse, müssen nicht forward deklariert werden. Sie sind durch die Definition der Klasse bereits bekannt.
Klassen-Variablen
Es gibt meist wenige Klassenvariblen. Denn diese sind „global“ innerhalb der Klasse. Alle Funktionen können auf diese Zugreifen.
class Token_stream {
...
private:
istringstream calculation;
bool full = false;
Token token_buffer;
};
Typisch ist, dass sie im private-Teil der Klasse stehen.
Lokale Variablen
In jeder Klassen-Funktion werden zur Verarbeitung auch lokale Variablen gebraucht.
Token Token_stream::get() {
char c;
Token t;
calculation >> c;
if (isdigit(c)) {
t.kind = 'n';
t.value = c;
} else if (c == '\0') {
t.kind = 'q';
}
return t;
}
Das Entwicklerportal gibt zu vielen Fragen Antworten. Interessant ist der Technische Überblick im Allgemeinen und die Vertiefung in die Beschreibung des physical Layers.
Anbindung an Android
Android App: Bluetootch Terminal
Hier ein Zusammenfassung aus der Spezifikation:
– Hat 2 Kabel: Serial Data (sda), Serial Clock (scl)
– Die Datenleitung ist im Ruhezustand auf ‚1‘ (pull up Widerstände notwendig)
– Start geht vom Datenkanal aus (siehe unten)
Serielle Datenübermittlung
Mit jedem Takt wird 1 Bit der Daten übermittelt.
Das Bit wird bei ‚1‘ im CLK ¨übernommen. Der Datenwechsel ist bei ‚0‘.

Start und Stop
Die Datenleitung steuert Start und Stop. Sie geht auf ‚0, wenn der CLK auf ‚1‘ ist. Normalerweise gibt es keinen Wechsel, wenn CLK auf ‚1‘ ist.
Empfangen der Bits
Mit jedem CLK wird 1 Bit empfangen.
Der Slave empfängt die Bits und legt sie in ein Register.
Schwingkreise können sich gegenseitig beeinflussen. So können sie sich z. B. ungewollt synchronisieren, was die Genauigkeit beschränken kann.
Frequenzdifferenz
Koppeln sich die zwei Systemen unterhalb der Lock-In-Schwelle, so schwingen danach beide mit derselben Frequenz.
N-mal Funktion parallel ausführen
__global__ void add( int *a, int *b, int *c){
. *c = *a + *b;
}
// Funktion add() wird 1-mal ausgeführt
add<<< 1, 1 >>>( dev_a, dev_b, dev_c );
// Funktion add() wird N-mal ausgeführt
add<<< N, 1 >>>( dev_a, dev_b, dev_c );
Die Variablen werden dadurch zu Arrays.
a -> a[N] , b -> b[N], c -> c[N]
Zugreifen auf die parallelen Prozesse
Jeder parallele Prozess läuft im Kernel in einem anderen Block. Jeder Block hat seine Id blockIdx.x .
a[1], b[1], c[1] laufen im Block 1.
c[0] = a[0] + b[0]
__global__ void add( int *a, int *b, int *c ) {
. c[blockIdx.x] = a[blockIdx.x] + b[blockIdx.x];
}
.
Eine Funktion kann N-mal aufgerufen werden. Daraus entstehen N parallele Blocks im Kernel, die man über ihre Block-Id ansprechen kann.
Innerhalb eines Blocks können mehrere Prozesse (Threads) gestartet werden. Dies ist notwendig, wenn ein Vektor, auf mehrere Blöcke eingeteilt wird.
Jeder Block hat seinen Vektor. Doch innerhalb eines Vektors entstehen mehrere Prozesse.
__global__ void add( int *a, int *b, int *c ) {
. c[ threadIdx.x blockIdx.x ] =
. a[ threadIdx.x blockIdx.x ] +
. b[ threadIdx.x blockIdx.x ];
}
Jedes Element des Vektors hat seinen Thread.
Einfaches Handling in Cuda
Cuda ist spezialisert auf das parallele Verarbeiten vieler Elemente (Vektoren).
Bsp:
8 Blocks (Funktion wird 8 mal ausgeführt) mit
Vektoren in der Funktion.
Jedes Element des Vektors kann per Thread-Index angesprochen werden.
Zugriff auf ein Element
Der Index des Elements ist einfach gebildet
int index = (blockIdx.x * Blocktiefe) + threadIdx.x int index = (blockId2.2 * 8) + threadId5.5 int index = ( 2 * 8 ) + 5 = 21

Elemente aus verschiedenen Threads und Blocks
Sofern man genau weiss, wie weit die Daten in den einzelnen Threads generiert sind, können Indizes unterschiedlicher Nummern verarbeitet werden
__global__ void add( int *a, int *b, int *c ) {
. c[index12] = a[index63] + b[index20];
}
Dazu braucht es jedoch die Synchronisation der Prozesse, die über synctrheads() organisiert werden kann.