Hallo,
ich sitze gerade an der Generierung eines Parsers für C Programme meines
Microcontrollers (bzw. Sensorknoten). Ich verwende als Compiler
normalerweise avr-gcc. Der verwendete Parser Generator ist JavaCC.
Hierfür habe ich eine Grammatik für ANSI C und eigene Grammatiken für
Spracherweiterungen, die ich in meine AVR C Programme mit einfließen
lassen will. Ich arbeite also an einem eigenen Präcompiler, welcher den
AVR C Code lässt wie er ist und meine Spracherweiterungen (XML , XPATH
...) in AVR C Code transformiert.
Mein Parser, der rein auf ANSI C basiert, wirft immer wieder Exceptions
für korrekten AVR C Code, da der Sprachumfang vom avr-gcc nicht
identisch ist. (Ist ja klar :-) )
Bevor ich mich selber daran mache, die Grammatik zu erweitern, wollte
ich daher fragen, ob jmd. eine fertige Grammatik für AVR C kennt.
In welcher Form sie vorliegt ist zunächst egal (gerne in JavaCC, Yacc,
ANTLR etc.) Hauptsache es ist der gedachte korrekte Sprachumfang (nicht
mehr und nicht weniger :-) ) Includes können evtl. nicht beachtet
werden, obwohl ich diese zur statischen Typüberprüfung benötige.
Kann mir jmd. helfen?
Vielen Dank
Nils
Syntaktisch sollte sich AVR-GCC-Code nicht von Standard-C unterscheiden.
Wo genau gibt es Probleme?
Aber musst du überhaupt den kompletten Code parsen? Sehr viel einfacher
wäre es, mit regulären Ausdrücken gezielte Ersetzungen vorzunehmen. Wie
sehen deine Spracherweiterungen denn aus?
Der originale Parser ist letztlich in den Quellen vom GCC enthalten
und in Bison (GNU's Yacc-Pendant) geschrieben. Aber der ist alles in
allem nicht wirklich klein.
Ich verwende zum Beispiel XML Konstrukte, die wiederum herkömmliche C
Variablen in sich aufnehmen können. Da ich eine statische Typüberprüfung
durchführe, benötige ich also die verwendeten Variablen aus dem C Code
(zumindest deren Typ). Die Typüberprüfung wiederum basiert auf einem
gegebenen XML Schema (oder DTD). Sinn der ganzen Aufgabe ist es XML
direkt bei der Programmierung nutzen zu können, wobei statisch validiert
wird. Das hat besonderen Nutzen bei Programmen mit XML Austausch (SOAP
Nachrichten etc.) Desweiteren sollen Xpath Ausdrücke direkt im C Code
verwendet werden können.
Was den Sprachumfang angeht, hier mal ein Beispiel, was von meinem
Parser nicht erkannt wird, aber in avr-gcc Programmen klappt:
1
xbuffer=(u_char*)MEM_TEST_BUF_ADDR;
Hier wirft der Parser eine Exception, da nach dem Stern kein
Variablenname erscheint. (auch wenn man MEM_TEST.... auflöst.)
Willst du die GCC-Erweeiterungen gegenüber ANSI-C (mittlerweile C90
genannt) wirklich nutzen?
Wenn nicht, kannst du die Erweiterungen mit den Compiler-Optionen
-ansi -pedantic
deaktivieren. Alles, was nicht dem Standard entspricht, wird dann als
Fehler angesehen.
Wenn du die GCC-Erweiterungen benutzen möchtest, kommst du nicht
umhin, den original GCC-Parser bzw. dessen Grammatik zu verwenden. Der
Parser der aktuellen Version (ich glaube, seit 4.0) ist handgemacht
(LL(1) per rekursivem Abstieg), da bin ich nicht sicher, ob es eine
parsergeneratorlesbare Form der Grammatik gibt. Prinzipiell kannst du
den Parser aber auch so nehmen, wie er ist. Schau dir mal
gcc/c-parser.c an). Das hätte den Vorteil, dass du bei neuen
GCC-Versionen mit deiner Software immer schnell wieder up-to-date
bist.
Die älteren Versionen verwenden einen tabellengesteuerten
LR(1)-Parser, der von bison (yacc-Ersatz) generiert wird. Die Datei
heißt dort c-parse.y.
Vielen Dank,
das sind schonmal viele gute Infos, die ich verdauen muss :-)
Ich habe hier noch eine ANTLR GCC Grammatik.
Die Sprachen GCC und AVR-GCC sind also identisch?
Dann würde das ja reichen.
Zu obigen Code:
standardkonformes C auch vor 99?
Also vielen Dank noch mal
Nils
> Die Sprachen GCC und AVR-GCC sind also identisch?
GCC ist ein (oder genau genommen mehrere) Compiler, der Fontends für
verschiedene Sprachen (C, C++, Fortran usw.) und Backends für
verschiedene Prozessoren (x86, AVR usw.) hat. Der AVR-GCC ist ein GCC,
der so konfiguriert ist, dass er C in AVR-Code übersetzt. Die C-Syntax
ist aber vom gewählten Backend unabhängig.
> standardkonformes C auch vor 99?
Standardkonform, seit es C gibt. Das ist einfach eine Zuweisung eines
Werts (vielleicht ein int), der vorher in einen u_char-Pointer
umgewandelt wird. Damit ein Compiler nicht meckert, müssen natürlich
xbuffer, u_char und MEM_TEST_BUF_ADDR vorher deklariert worden sein.
Danke nochmal,
ich habe jetzt den Fehler gefunden.
Hierzu den ganzen Anfang
1
u_charmem_test_checkMem(void){
2
volatileu_char*xbuffer;
3
xbuffer=(u_char*)MEM_TEST_BUF_ADDR;
4
u_shorti=0;
5
u_charj=0;u_chardata;
6
u_charerrors=0;
7
u_charreturn_val=0;
8
data=0;
9
for(i=0;i<MEM_TEST_BUF_SIZE;i++){
10
xbuffer[i]=data;
11
if(xbuffer[i]!=data){
12
_print_error(i,xbuffer[i],data);
13
return_val=1;
14
if(errors++>MAX_NR_ERRORS-2)break;
15
}
16
}
17
data=1;
18
for(j=0;j<8;j++){
19
errors=0;
20
for(i=0;i<MEM_TEST_BUF_SIZE;i++){
21
xbuffer[i]=data;
22
if(xbuffer[i]!=data){
23
_print_error(i,xbuffer[i],data);
24
return_val=1;
25
if(errors++>MAX_NR_ERRORS-2)break;
26
}
27
}
28
data=data*2;
29
}
30
returnreturn_val;
31
}
Das Problem liegt darin, dass in meiner Grammatik zuerst alle
Variablendeklarationen kommen müssen ehe der weitere Code kommt.
Ich bin mir nicht sicher, ob ein anderer Weg erst seit 99 offiziell
Standard ist?! Wenn ich nur die ersten beiden Zeilen der Methode im
Block habe, funktioniert das parsen einwandfrei.
Daher werde ich mich an die Grammatik setzen müssen. Dann dürfte das
aber kein Problem mehr sein.
Vielen Dank
Nils
Es liegt also daran, dass solange ich mich im Zustand
"Variablendeklaration und sofortige Initialisierung" befinde, alles
funktioniert. Wenn ich zum ersten Mal eine Zuweisung hab, gelange ich in
den "Anweisungsblock". Ab jetzt sind keine Deklarationen mehr erlaubt.
Also gehe ich davon aus, dass die Methoden zunächst alle Deklarationen
und dann die Anweisungen haben. Ich glaube das war mal Standard und ist
in meinem C Buch auch so angegeben. (Wie auch bei Pascal)
ANSI C99 erlaubt wohl auch eine Durchmischung oder?
Danke Nils
_attribute_ und der folgende Code wird von meinem Parser nicht
erkannt,
stammt wohl aus GNU-C ??
Wo kann ich die Syntax von diesen "special types" finden?
Hallo,
so ich habe nun meine Arbeiten an einer GNU-C Grammatik für JavaCC fast
abgeschlossen. Funktioniert alles sehr gut (ausser Includes automatisch
verarbeiten)
Probleme bereiten mir weiterhin einige kleine Befehler.
Der Ausdruck
lässt sich einfach nicht parsen.
avr-gcc erkennt ihn wunderbar.
Ist der Befehl nun nur in avr-gcc enthalten oder auch im reinen GnuC?
ändere ich den Befehl in
klappt das parsen einfandfrei.
Die "" gehören aber nunmal eigentlich zu SADDR_FMT und das erstellen
eines Tokens für bt-cmd@ hat noch nicht geklappt.
Vielleicht kann mir jmd. näheres zu diesem ungewöhnlichen Befehl sagen.
Danke
Nils
> lässt sich einfach nicht parsen.
Könnte das daran liegen, dass du keine Include-Dateien auswertest und
daher nicht weißt, dass SADDR_FMT zu einem string literal expandiert?
Nach dem Preprozessing kommt da also sowas raus wie:
1
sprintf(prompt,"[bt-cmd@""%u""]$ ",...
> Ist der Befehl nun nur in avr-gcc enthalten oder auch im reinen> GnuC?
Es ist ISO-C90. Stichwort: string concatenation.
Der AVR-GCC hat eigentlich keinerlei Syntaxerweiterungen gegenüber dem
GCC ,,aus der Dose''. OK, eine hat(te) er: binäre Konstanten (mit 0b
eingeleitet), aber die sind nun mittlerweile auch im ,,richtigen'' GCC
drin.
> ändere ich den Befehl in>
> Der Ausdruck> sprintf(prompt, "[bt-cmd@"SADDR_FMT"]$ ", SADDR(addr));> lässt sich einfach nicht parsen.
Das liegt vielleicht daran, daß der C-Präprozessor die Zeichenketten
verbindet. Der C-Compiler bekommt so etwas nie zu sehen.
Klaus
Klaus Falser wrote:
> Das liegt vielleicht daran, daß der C-Präprozessor die Zeichenketten> verbindet. Der C-Compiler bekommt so etwas nie zu sehen.
Falsch.
Und was ist richtig?
also es tritt auch ohne die @ Zeichen auf (Gehe von BTNut Applikationen
aus).
Für mich sieht das nach fehlender "Verbindung" aus.
Was ist es nun wirklich?
Ups...hatte den Beitrag oben übersehen:
Ja das mit dem Include ist natürlich richtig ....
wie bereits erwähnt, bereiten die mir ja Probleme.
Werde mir noch eine Lösung einfallen lassen müssen.
> Und was ist richtig?
Dass der Präprozessor zwar den Makro ersetzt, aber die verbleibende
string concatenation (also das Ablegen zweier aufeinander folgender
string literals als ein ganzes) macht der Compiler.
In meinen K&R Ansi C Handbuch (2. Auflage) steht bei Preprozessor, Seite
226, Phase 4 :
"Ersatzdarstellungen in Zeichenkonstanten und konstanten Zeichenketten
(...) werden durch äquivalente Zeichen ersetzt; anschließend werden
benachbarte konstante Zeichenketten aneinandergehängt."
Ich hätte das schon so interpretiert daß der Präprozessor die
Zeichenketten zu einer zusammenfasst.
Klaus