# Themen zum Preprozessor



## Barnee (1 Februar 2006)

Ich starte hiermit den Thread für Themen rund um den Preprozessor.

Gruß Barnee


----------



## Barnee (1 Februar 2006)

*C-Quelltexte einlesen*

Unabhängig davon ob es sich um den PP oder Parser handelt, gilt es einmal festzulegen, mit welchem Speichermodell wir arbeiten wollen. Legen wir entsprechend den Urzeiten Metafiles an, oder allocieren wir den benötigten Speicher dynamisch?

Ich denke, da zu diesen Zeiten der Speicher keine Kostenfrage mehr ist, sollten wir vorzugsweise mit dynamisch angelegtem Speicher hantieren. M.E. ist bei einem S7-Projekt nicht zu erwarten, das dies die Grenzen des zur Verfügung stehenden Speichers sprengen würde. Dies könnte u.U. jedoch auftreten, wenn jemand alle Bausteine eines S7-Projektes in einem C-File abspeichert. Aber auch dieses Problem lässt sich lösen, da doch die Bausteine innerhalb eines C-Projektes auch jeweils als abgeschlossene Einheiten abzugrenzen sind, d.h. der Compiler arbeitet grundsätzlich immer nur einen Baustein ab, der dann nach der Fertigstellung auf die HD geschrieben werden kann, um anschließend den belegten Speicher wieder freizugeben. Bei geschickter Handhabung kann somit eine Fraktionierung des Speicher sicher verhindert werden, was die Gefahr eines Compilerkollapses ausschließt.

Der Parser liest somit die Bausteine immer als ganzes in den Speicher ein. Hier ist zunächst eine Schwierigkeit vorhanden. Wenn man davon ausgeht, dass eine C-Datei immer nur einen Baustein enthalten würde, wäre diese Schwierigkeit nicht vorhanden, da man aus der Größe der Quelldatei den benötigten Speicher leicht bestimmen kann. Doch was ist, wenn z.B. 10 Bausteine in einer C-Quelle vorhanden sind?

Eine Möglichkeit, die mir gerade einfällt, wäre, erst einmal eine Annahme über den benötigten Speicher zu machen. In den reservierten Speicher wird zunächst der entsprechende Anteil des C-Quelltextes eingelesen. Jetzt prüft der PP die geschweiften Klammerpaare ab, auf eine geöffnete Klammer kann entweder eine schließende Klammer oder eine weitere öffnende Klammer folgen usw.usf. Man zählt die Klammern, eine öffnende Klammer inkrementiert und eine schließende Klammer dekrementiert. Wird dabei von 1 auf 0 herunter gezählt, ist das Ende der Funktion (FC oder FB) erreicht! Wird die "0" vor Ende des reservierten Speichers erreicht, dann befindet sich ein kompletter Baustein im Speicher, ist dass jedoch nicht der Fall, dann muss ein weiterer Speicher mit angenommener Größe reserviert werden und der nächste Teil des C-Quelltextes wird eingelesen. Die Zählung der Klammerpaare wird dann fortgesetzt. Wird jetzt der Vorgang von 1 nach 0 ermittelt, dann ist die Größe des insgesamt benötigten Speichers bekannt. Konnte auch dieses Mal das Ende des Bausteins nicht ermittelt werden, dann wird der Vorgang durch Einrichtung eines weiteren Speichers wiederholt. Ich hoffe nicht, dass jemand einen so großen Baustein geschrieben hat, der 750.000 Zeilen enthält, denn dann wären etwa 50 MB Speicher erforderlich.

Wurde bisher nur EIN Speicherbereich reserviert, so befindet sich der gesamte Baustein in einem zusammenhängenden Speicherbereich, so dass keine weiteren Maßnahmen in diesem Zusammenhang erforderlich sind. Wurde dagegen der Baustein in mehreren Abschnitten eingelesen, so sollte ein zusammenhängender Speicher mit der entsprechenden Größe reserviert werden. In diesen Speicher werden dann die Teilquellen lückenlos verschoben, danach werden die ursprünglich reservierten Teilbereich wieder freigegeben.

So, das war's erst einmal. Ich stelle das hier zur Diskussion. Vielleicht weiss jemand eine bessere Möglichkeit?

Gruß Barnee


----------



## Speedy (3 Februar 2006)

Hallo zusammen,

gibt es irgendwelche Sachen die der Preprozessor bei unterschiedlichen CPUs berücksichtigen muss. Kennt z.B. die S7-200 float und double.  Sind die Zahlenbereiche bei allen CPUs identisch.

Welche CPUs wollen wir überhaupt unterstützen? 

Gruß Speedy


----------



## Rainer Hönle (3 Februar 2006)

Die 200er ist so ein bisschen ein Sonerthema bei Siemens. Kommt ursprünglich von ti (so heißt es). Hat fast nichts mit der 300er und 400er zu tun, außer gewisse Gemeinsamkeiten bei der Kommunikation. Mir wäre es arg Recht, wenn wir uns für den Anfang auf die "großen" konzentrieren könnten.


----------



## Jochen Kühner (3 Februar 2006)

*SFB's/SFC's*

es ist ja auch wichtig für uns welche SFB's und SFC's von der jeweiligen Cpu unterstützt werden...

Gut am anfang vieleicht noch nicht, aber falls wird dann eine lib zur stringverarbeitung einbauen muss ja klar sein ob z.b. der sfc20 (blockmove vorhanden ist oder nicht)


----------



## Rainer Hönle (3 Februar 2006)

Da müssen wir halt Codegenerierungsoptionen ähnlich Prozessor im VirtualStudio einbauen, damit die Steureungseigenheiten möglichst optimal unterstützt werden. Ineffizienten Code gibt es bereits genügend!


----------



## Barnee (3 Februar 2006)

Hallo @All

Vorab mal etwas grundsätzliches, ich verstehe unter einem PP einen Automaten, der sich ausschließlich mit Formalien beschäftigt. Vielleicht kann man einen PP aus einer Opensource-Quelle übernehmen? Ich weiß es nicht! Nach meiner Ansicht macht ein PP eine mögliche C-Quelle nur handlicher, d.h., um es noch einmal auf die m.E. wichtigsten Punkten eines PP zu konzentrieren:
-- Eine gut strukturierte C-Quelle enthält viele Leerzeichen/Tabs für Einrückungen, die für den eigentlichen Compiliervorgang nicht erforderlich sind. Diese gilt es zu beseitigen.
-- Eine gut dokumentierte C-Quelle enthält viele Kommentare, die entweder in einer Zeile stehen oder über mehrere Zeilen sich erstrecken können. Auch diese Kommentare sind für den eigentlichen Compiliervorgang nicht erforderlich sind. Diese gilt es zu beseitigen.
-- Mit "#define" können Makros verabredet werden. Diese Makros müssen *vor* der Ausführung des Parsers substituiert werden.
-- Funktionen, die in Libraries angesprochen werden, werden in Header-Files durch ihren Prototypen repräsentiert. Auch diese (#include)-Header-Files müssen mit eingelesen werden und müssen vorerst durch den PP zu ähnlichen Bedingungen wie die eigentliche C-Quelle behandelt werden (Achtung: Compiler-Direktiven).
-- Es müssen alle Variablen erfaßt und (Compiler-interne) Referenzen darauf abgebildet werden. Aber anders als in einem wirklichen Compilat für einen uP, beziehen sich diese Referenzen, ausschließlich auf Variablen, die für die Schnittstellen-Parameter eines S7-FCs oder S7-FBs verwendet werden, also Var_input, Var_ouput, Var_inout, Var_temp und Var.
-- Es werden Klammerungen untersucht, d.h. die in C möglichen Klammerungen müssen *immer* zu einem formal abgeschlossenen Ausdruck führen. (Ich will das hier an dieser Stelle nicht weiter vertiefen, weil ich zu diesem Teil zu einem späteren Zeitpunkt noch meine Anmerkungen ausführen möchte.)

Wenn der PP die v.g. Punkte abgearbeitet hat, was nach m.E. in einem Durchgang (Pass) erfolgen sollte, dann steht eine Zwischendatei zur Verfügung, die nur formal bereinigt ist und noch *keine* spezifischen Aussagen zu den im C-Quelltext enthaltenen C-Konstruktionen festgelegt hat. IMHO verhält sich der PP bis zu diesem Punkt (fast) völlig neutral, was das Ziel des später fertiggestellten Compilats betrifft. Ich lasse mich aber gerne belehren, wenn anderweitige Erkenntnisse zu einem PP vorliegen.



			
				Speedy schrieb:
			
		

> Hallo zusammen,
> 
> gibt es irgendwelche Sachen die der Preprozessor bei unterschiedlichen CPUs berücksichtigen muss. Kennt z.B. die S7-200 float und double.  Sind die Zahlenbereiche bei allen CPUs identisch.
> 
> ...





			
				Rainer Hönle schrieb:
			
		

> Die 200er ist so ein bisschen ein Sonerthema bei Siemens. Kommt ursprünglich von ti (so heißt es). Hat fast nichts mit der 300er und 400er zu tun, außer gewisse Gemeinsamkeiten bei der Kommunikation. Mir wäre es arg Recht, wenn wir uns für den Anfang auf die "großen" konzentrieren könnten.



Wie oben schon gesagt, ist es nach m.E. für den PP (gilt nur für den PP nicht für den Parser) völlig Schnurz, welche CPU am Ende mit dem fertigen Compilat beglückt werden soll. Bei S5-CPUs wäre es schon wichtig zu wissen gewesen, welche "Onboard"-Funktionen vorhanden sind, da gab es zwischen 115, 135 und 155 schon reichlich Unterschiede. Aber gottlob stellt sich für uns die S5-Frage nicht. Bei S7-300 und S7-400 wird es sicher auch Unterschiede geben, diese Berücksichtigung kann man sicher durch "#include" spezifisch bekannt geben. Grundsätzlich könnte ich mir den Compiler auch für die Anwendung bei einer S7-200 vorstellen, ob das jedoch Sinn macht, entzieht sich z.Zt. meiner Erkenntnis, wobei ich dann aber eher den Eindruck habe, das wir in einem solchem Falle mit Kanonen auf Spatzen schießen.

Nach meinem Wissensstand (man mag mich widerlegen) verfügen die CPUs der S7-300/400 ausschließlich über eine Gleitkommaverarbeitung mit Single-Precision (4 Byte), Double-Precision (8 Byte) würde damit schon mal ausscheiden. Eine Verarbeitung mit höherer Genauigkeit wäre jedoch möglich, wenn man die Parameterübergabe auf der Basis des ANY-Pointers gestalten würde und eigene Funktionen hierfür schaffen würde - Zukunftsmusik? - vielleicht, eine Wertausgabe wäre über OPC an externe Rechner möglich.



			
				Jochen Kühner schrieb:
			
		

> es ist ja auch wichtig für uns welche SFB's und SFC's von der jeweiligen Cpu unterstützt werden...
> 
> Gut am anfang vieleicht noch nicht, aber falls wird dann eine lib zur stringverarbeitung einbauen muss ja klar sein ob z.b. der sfc20 (blockmove vorhanden ist oder nicht)


Siehe oben. SFCs und SFBs sind wie der Name schon sagt Funktionen und Funktionsbausteine des S7-Systems. Der Zugriff zu diesen Funktionen (ich fasse das mal zusammen, mir ist diese Siemens-Terminologie etwas lästig, weil der Unterschied ja nur Siemens-spezifisch ist) erfolgt aus der Sicht unseres C-Compilers wie auf eine gewöhnliche Library, d.h. wir werden für diese SFCs und SFBs C-spezifische Headerfiles erstellen, die dann durch unseren C-Compiler berücksichtigt werden.



			
				Rainer Hönle schrieb:
			
		

> Da müssen wir halt Codegenerierungsoptionen ähnlich Prozessor im VirtualStudio einbauen, damit die Steureungseigenheiten möglichst optimal unterstützt werden. Ineffizienten Code gibt es bereits genügend!



Ich kenne denn PP vom VirtualStudio nicht, vielleicht kann Rainer uns da mal etwas mehr von vorstellen.

Beispiele von ineffizienten Code muss ich mir täglich anschauen, das was z.B. SCL an AWL zusammenbastelt, ist wirklich katastrophal. Wer CFC kennt, weiss, dass man mit CFC FBs basteln kann (ich sage bewusst *basteln*). Diese Bausteine kann man in SCL übersetzen. Die Sicht in solche Bausteine stellt mir stets die Haare senkrecht auf. Mit einer Nachbehandlung in SCL verliert der Baustein damit seinen Bezug zum CFC (was mir aber egal ist) aber auch gleichzeitig etwa 50% seines überflüssigen Codes. Eine weitere Nachbehandlung in AWL bringt nochmals eine Reduzierung um beachtliche Prozentzahlen. Hier mal ein SCL-Beispiel zum Vergleich von zwei 16-Bit-Integern (ich beschränke mich nur auf die Darstellung des Wesentlichen):


```
gt := IN1 >  IN2;
ge := IN1 >= IN2;
eq := IN1 == IN2;
le := IN1 <= IN2;
lt := IN1 <  IN2;
```
Sieht eigentlich elegant aus, aber das gibt der SCL-Übersetzer als AWL-Code aus:

```
L    #IN1
L    #IN2
>I
=    #gt
L    #IN1
L    #IN2
>=I
=    #ge
L    #IN1
L    #IN2
==I
=    #eq
L    #IN1
L    #IN2
<=I
=    #le
L    #IN1
L    #IN2
<I
=    #lt
```
Nicht optimal!!!!!Und das wäre optimal:

```
L    #IN1
L    #IN2
>I
=    #gt
>=I
=    #ge
==I
=    #eq
<=I
=    #le
<I
=    #lt
```

Gruß Barnee


----------



## Rainer Hönle (3 Februar 2006)

Barnee schrieb:
			
		

> Nicht optimal!!!!!Und das wäre optimal:
> 
> ```
> L    #IN1
> ...


Das automatisch hinzubekommen ist nicht nur optimal sondern *genial*. Das muss der Codegenerierer sämtliche Registerinhalte "im Kopf" haben, dann geht das. Ist anzustreben aber nicht einfach. Die heutigen Compiler machen hier manches auch in mehreren Durchläufen nacheinander.
Anm.: Ich nenne die Entwicklungsumgebung meines Freundes Bill (the Gates) liebevoll VirtualStudio. Weil Visual ist es m.E. noch nicht ganz.


----------



## Speedy (4 Februar 2006)

Hallo zusammen,

habe mich mal so im Netz umgeschaut ob man etwas findet was man als Ausgangspunkt nehmen könnte. Bin dabei auf einen ‚C and T preprocessor, and integrated lexer’ gestoßen.

Sicher müsste man noch ein paar Änderungen und einen ‚Frontend’ machen aber dass sollte nicht so viel arbeit sein.

Wünsche Euch noch ein schönes Wochenende.

Gruß Speedy


----------



## Barnee (4 Februar 2006)

Hallo Speedy

Danke für den Tip. Ich hatte gestern auch schon mal im Netz geschaut und verschiedene Links gefunden, doch der von dir gefundene war (leider :shock: ) nicht dabei. Ich habe schon mal einen kurzen Blick in den Quelltext geworfen und wie es scheint, könnte man darauf aufsetzen, was uns viiiiiieeeeel Arbeit ersparen würde.

Meine Idee ist nach wie vor, nicht alles sequentiell zu entwickeln, sondern in verschiedenen Arbeitsbereichen, so weit es geht, parallel zu arbeiten. Mit meinem Einstieg in die Diskussion um den PP hatte ich beabsichtigt, unser Ziel etwas näher zu spezifizieren, da doch die Meinungen um das, was ein PP machen sollte, etwas quer Beet gehen.

Bei weiterem Nachdenken bin ich nun an den Punkt angekommen, dass es jetzt schon sehr wichtig ist, zuvor den Rahmen, der die Notwendigkeiten für unser Projekt einschließen soll, näher zu definieren. Als ich meine ersten Gedanken zu einzelnen Themen niederschrieb, war ich noch nicht soweit, zumal man sich naturgemäß lieber mit "konkreten" Dingen beschäftigt als über Abstraktionen nachzudenken. Ich habe jetzt ein neues Ziel ausgemacht, von dem ich der Meinung bin, das wir das vorrangig angehen sollten, ich werde in dem Thread "Gemeinsamkeiten C <-> Step7" http://www.sps-forum.de/phpBB2/viewtopic.php?t=6652 beginnen, meine Gedankengänge hierzu nieder zu schreiben.

Gruß Barnee


----------



## Rainer Hönle (7 Februar 2006)

Bei der Darlegung, was richtiger und optimaler Code ist, ist mir noch etwas eingefallen. Sollten wir einen Optimizer vorsehen? Der müsste dann das Wissen über die Akkuinhalte haben und ggf. auch Code-Umorganisationen vornehmen.

Beispiel:

```
L    #IN1 
L    #IN2 
>I 
=    #gt 
NOT
=    #le
>=I 
=    #ge 
NOT
=    #lt
==I 
=    #eq
```
Der kann dann auch arbeiten, wenn die Akkus für die Vergleiche in unterschiedlicher Reihenfolge geladen werden und ggf. die Bedingungen negieren.
Klar ist aber auch, dass wir zuerst etwas brauchen, das wir optimieren können :!: Also bitte mitmachen und für die einzelnen Arbeitsbereiche melden bzw. eintragen :!: Tut was, nicht dass Barnee noch die Lust verliert :evil:


----------



## Barnee (7 Februar 2006)

*Optimizer*



			
				Rainer Hönle schrieb:
			
		

> Bei der Darlegung, was richtiger und optimaler Code ist, ist mir noch etwas eingefallen. Sollten wir einen Optimizer vorsehen? Der müsste dann das Wissen über die Akkuinhalte haben und ggf. auch Code-Umorganisationen vornehmen.
> 
> Beispiel:
> 
> ...


Na, kürzer geht's wohl nimmer, was dieses Beispiel anbelangt. Es gäbe noch eine Variante, die ausschließlich mit den Vergleichen _>I_ bzw. _<I_ auskommen würde. Aber schlussendlich bliebe es trotzdem bei 12 Zeilen     

Klar doch muss ein Optimizer her, man sollte doch sich nicht mit Siemens auf eine Stufe stellen, wir können das besser  8)  8)  8) 

Rainer, wie wäre es, wenn du dich dieses Parts annehmen würdest? Ich glaube, dass da unsere Gedankengänge sich ähnlich sind. Bliebe aber zu beachten, das es wohl auch CPUs gibt, die nur mit zwei Akkus ausgerüstet sind, da müsste wohl ggf. eine Projektvoreinstellung berücksichtigt werden. Mich beschäftigen i.A. solche Gedankengänge im Hinblick auf die unter ANSI-C üblichen Speicherklassen, die dieses Thema etwas berühren, wenn ich z.B. an die Speicherklasse _register_ denke. Ich habe da i.A. aber noch keinen Plan von, weil ich das Thema Speicherklassen noch nicht bewusst beackert habe.

Gruß Barnee


----------



## Rainer Hönle (8 Februar 2006)

*Re: Optimizer*



			
				Barnee schrieb:
			
		

> Na, kürzer geht's wohl nimmer, was dieses Beispiel anbelangt. Es gäbe noch eine Variante, die ausschließlich mit den Vergleichen _>I_ bzw. _<I_ auskommen würde. Aber schlussendlich bliebe es trotzdem bei 12 Zeilen


Klar, die Codelänge in Zeilen ist das eine, die Codelänge in Bytes oder die Ausführungszeit das andere. Da muss ich mich auch noch schlau machen und mit dem Spezialisten bei mir im Hause reden. 



			
				Barnee schrieb:
			
		

> Rainer, wie wäre es, wenn du dich dieses Parts annehmen würdest? Ich glaube, dass da unsere Gedankengänge sich ähnlich sind. Bliebe aber zu beachten, das es wohl auch CPUs gibt, die nur mit zwei Akkus ausgerüstet sind, da müsste wohl ggf. eine Projektvoreinstellung berücksichtigt werden.


Mach ich gerne. Hatte schon immer eine Vorliebe für effizienten kompakten Code. Kommt wahrscheinlich noch aus der Zeit als jedes Byte richtig Geld gekostet hat :wink: 
Das mit den zwei oder vier Akkus ist meiner Meinung nach etwas seltsam implementiert. Warum benötige ich ein PUSH um etwas von 1-> 2-> 3-> 4 -> NULL zu bringen, aber von 1-> 2-> NULL geht das automatisch? Es wäre doch einfach gewesen mit L alle Akkus weiter zu schieben. Oder kostet dies so viel Rechenzeit? Na gut, das ist eine andere Baustelle.


----------

