|
JLI Spieleprogrammierung
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
AFE-GmdG JLI MVP
Alter: 45 Anmeldedatum: 19.07.2002 Beiträge: 1374 Wohnort: Irgendwo im Universum... Medaillen: Keine
|
Verfasst am: 23.08.2003, 21:49 Titel: [c#] brauche Hilfe bei Parser (Precompiler-Teil) |
|
|
Hallo, Leute!
Ich Realisiere gerade für einen Interpreter einen Precompiler, mit dem ich neben Dingen wie #include, #define usw. auch Kommentare entfernen will (einzeilige wie mehrzeilige)
Das Entfernen von einzeiligen Kommentaren funktioniert schon (siehe Code) aber für mehrzeilige Kommentarehabe ich noch keine Idee.
Meines Erachtens ist die Lösung für die einzeiligen Kommentare auch noch nicht gerade Perfekt. Sie berücksichtigt zwar alle eventuell auftretenden Fälle, arbeitet aber recht langsam. Ist es vielleicht Möglch, mit Hilfe von RegExpressions die Strings zu verarbeiten, so dass ich auf die umständlichen if/else if/else verzichten kann? Ich habe noch nie selbst mit RegEx gearbeitet.
Die fertige Ausgabe wird vorerst zu Testzwecken nur auf der Konsole ausgegeben und sollte keinerlei Kommentare mehr enthalten. Später werde ich die Ausgabe in einer ArrayList Speichern und weiterverarbeiten (Die Precompilerdirektiven, die weiter unten bereits angedeutet sind)
Code: |
public bool Run() {
String Line;
int row=0; // Zeilennummer
int i=0; // Positionsindex für Textsuche;
while(sr.Peek()>0) { // sr ist eine geöffnete Datei (StreamReader)
Line=sr.ReadLine().Trim();
row++;
// Einzeilige Kommentare entfernen wobei auf Strings und Chars geachtet werden muß
if((i=Line.IndexOf("//"))>=0) {
if(i==0) // Ist ganze Zeile Kommentar
continue;
bool InString=false;
bool InChar=false;
char[] c=Line.ToCharArray();
for(i=0; i<c.GetUpperBound(0)-1; i++) {
if(!InString&&c[i]=='\'') { // Char startet oder endet
InChar=!InChar;
}
if(InChar&&c[i]=='\\'&&c[i+1]=='\'') { // Ein ' innerhalb eines Char
i++;
continue;
}
if(InChar&&c[i]=='\\'&&c[i+1]=='\\') { // Ein \ innerhalb eines Char
i++;
continue;
}
if(!InChar&&c[i]=='"') { // String startet oder endet
InString=!InString;
}
if(InString&&c[i]=='\\'&&c[i+1]=='"') { // Ein " innerhalb eines Strings
i++;
continue;
}
if(InString&&c[i]=='\\'&&c[i+1]=='\\') { // Ein \ innerhalb eines Strings
i++;
continue;
}
if(!InString&&!InChar&&c[i]=='/'&&c[i+1]=='/') { // Ab hier ist Rest der Zeile Kommentar
Line=Line.Substring(0, i-1);
break;
}
}
}
//TODO: Mehrzeilige Kommentare entfernen wobei auf Strings geachtet werden muß
// auf Leerzeile testen
if(Line=="") // Leerzeile
continue;
// auf Precompiler-Anweisung testen
if(Line.StartsWith("#")) { // Precompiler-Anweisung
if(Line.StartsWith("#include ")) {
//TODO: Testen auf gültigen Dateinamen
continue;
} else if(Line.StartsWith("#define ")) {
} else if(Line.StartsWith("#if ")) {
} else if(Line.StartsWith("#ifdef ")) {
} else if(Line.StartsWith("#ifndef ")) {
} else if(Line.StartsWith("#else")) {
} else if(Line.StartsWith("#endif")) {
} else if(Line.StartsWith("#undef ")) {
} else if(Line.StartsWith("#warning ")) {
} else if(Line.StartsWith("#error ")) {
} else {
Console.WriteLine("Ungültige Precompiler-Anweisung in {0}:{1}", Path.Combine(GetPath(), GetFile()), row);
return false;
}
}
Console.WriteLine("Zeile {0}: {1}", row, Line);
}
return true;
}
|
Wer kann mir in diesem doch recht speziellem Fall helfen?
Eine "RegExLösung" die die Kommentare einfach "Wegzaubert" und dabei auch noch beachtet, daß auch Innerhalb von Strings oder Chars // oder /* vorkommen dürfen wäre mir am liebsten, aber wie gesagt, ich hab mit RegEx noch nie gearbeitet... _________________
CPP: | float o=0.075,h=1.5,T,r,O,l,I;int _,L=80,s=3200;main(){for(;s%L||
(h-=o,T= -2),s;4 -(r=O*O)<(l=I*I)|++ _==L&&write(1,(--s%L?_<(L)?--_
%6:6:7)+\"World! \\n\",1)&&(O=I=l=_=r=0,T+=o /2))O=I*2*O+h,I=l+T-r;} |
|
|
Nach oben |
|
|
Christian Rousselle Site Admin
Alter: 48 Anmeldedatum: 19.07.2002 Beiträge: 1630
Medaillen: Keine
|
Verfasst am: 24.08.2003, 00:25 Titel: |
|
|
Warum interessierst du dich für char, string usw. wenn du nur #define, #if, #endif und Kommentare rausnehmen willst?
Es ist schon spät, aber ich würde sowas machen:
Code: |
char GetNextChar(void); // holt den nächsten character, schmeißt whitespace-Zeichen weg
char c;
while(!feof(f))
{
c = GetNextChar();
if('#' == c)
{
c = GetNextChar();
if('d' == c) parsePPDefine();
else if('i' == c) parsePPIf();
else Error();
}
else if('/' == c)
{
c = GetNextChar();
if('/' == c) ReadComment(); // bis zum nächsten Zeilenumbruch alles überlesen
else if('*' == c) ReadMLComment(); // bis zum nächsten */ alles überlesen
// else nichts tun, denn es ist Code
}
}
|
C. |
|
Nach oben |
|
|
AFE-GmdG JLI MVP
Alter: 45 Anmeldedatum: 19.07.2002 Beiträge: 1374 Wohnort: Irgendwo im Universum... Medaillen: Keine
|
Verfasst am: 24.08.2003, 10:31 Titel: |
|
|
Christian Rousselle hat Folgendes geschrieben: | Warum interessierst du dich für char, string usw. wenn du nur #define, #if, #endif und Kommentare rausnehmen willst? |
Wenn innerhalb des zu parsenden Quelltextes eine Codezeile wie diese ist:
Code: | String /*+*/="TestString mit // und /* */-Zeichen sowie \"Anführungsstriche\""; //Kommentar bis Ende der Zeile
|
muß der Parser trotzdem ordendlich Funktionieren. _________________
CPP: | float o=0.075,h=1.5,T,r,O,l,I;int _,L=80,s=3200;main(){for(;s%L||
(h-=o,T= -2),s;4 -(r=O*O)<(l=I*I)|++ _==L&&write(1,(--s%L?_<(L)?--_
%6:6:7)+\"World! \\n\",1)&&(O=I=l=_=r=0,T+=o /2))O=I*2*O+h,I=l+T-r;} |
|
|
Nach oben |
|
|
Christian Rousselle Site Admin
Alter: 48 Anmeldedatum: 19.07.2002 Beiträge: 1630
Medaillen: Keine
|
Verfasst am: 24.08.2003, 11:05 Titel: |
|
|
Okay,
aber dann muss du diese if..else if nur noch um
Code: |
else if(c == '"') ReadString(); // String überlesen
else if(c == '\'') ReadChar(); // char überlesen
|
erweitern. Man könnte aus dem GetNextChar() auch ein GetNextToken() machen, dass dann anstatt einem Zeichen ein Token ließt. D.h. dass die Funktion wenn sie auf Zeichen wie \" merkt dass es ein normales Zeichen ist, bei ", das einen String einleitet dann TOKEN_STARTSTRING zurückgibt. Dann könnte man sowas machen:
Code: |
t = GetNextToken();
if(t == TOKEN_STARTSTRING)
{
while(t != TOKEN_ENDSTRING)
{
GetNextToken();
}
}
else if(t == TOKEN_SL_COMMENT)
{
// Komplette Zeile überlesen, bis TOKEN_NEWLINE
}
else if(t == TOKEN_ML_COMMENTSTART)
{
while(t != TOKEN_ML_COMMENTEND)
{
GetNextToken();
}
}
|
C. |
|
Nach oben |
|
|
The Lord of Programming Living Legend
Alter: 37 Anmeldedatum: 14.03.2003 Beiträge: 3122
Medaillen: Keine
|
Verfasst am: 24.08.2003, 11:18 Titel: |
|
|
Wenn du auf Mehrzeilige kommentare testen willst, würde ich einfach eine Variable für den "Status" des Zeichens machen.
Z.B. Wenn du ein " ließt, setzt du den Status auf Zizat(d.h. Kommentarzeichen wird ignoriert). Beim zweiten Lesen des " setzt du den Status wieder auf Normal(d.h. Kommentarzeichen wirkt).
Wenn jetzt /* gelesen wird, testest du, ob der Status Normal ist(sonst wird das Kommentarzeichen als Zeichen des Quellcodes interpretiert). Dann setzt du den Status auf Mehrzeilenkommentar. Wenn du nun auf */ triffst, muss der Status auf Mehrzeilenkommentar stehen und der Kommentar ist zu Ende. _________________ www.visualgamesentertainment.net
Current projects: RDTDC(1), JLI-Vor-Projekt, Tetris(-Tutorial), JLI-Format
(1) Realtime Developer Testing and Debugging Console
Anschlag, Anleitung zum Atombombenbau, Sprengkörper...
Hilf Schäuble! Damit er auch was findet... |
|
Nach oben |
|
|
AFE-GmdG JLI MVP
Alter: 45 Anmeldedatum: 19.07.2002 Beiträge: 1374 Wohnort: Irgendwo im Universum... Medaillen: Keine
|
Verfasst am: 24.08.2003, 14:19 Titel: |
|
|
Eine Funktion wie "GetNextToken" ist eine gute Idee, damit kann ich sicherlich recht gut Arbeiten.
Als Status kann ich ja dann z.B. InString, InChar, SingleKomment, MultiKomment usw. nutzen.
Ewnn die Funktion "GetNextToken" dann auch noch reservierte Wörter, Variablennamen usw. Filtert, komme ich sicherlich schneller zu meinem gewünschtem Ergebnis.
Eine Liste von Regeln, die besagen, welcher Status wann auftreten darf sollte nicht allzuschwer zu erstellen sein.
Ein PAP auf Papier ist in solchen Fällen immer Hilfreich - und den erstell ich jetzt. _________________
CPP: | float o=0.075,h=1.5,T,r,O,l,I;int _,L=80,s=3200;main(){for(;s%L||
(h-=o,T= -2),s;4 -(r=O*O)<(l=I*I)|++ _==L&&write(1,(--s%L?_<(L)?--_
%6:6:7)+\"World! \\n\",1)&&(O=I=l=_=r=0,T+=o /2))O=I*2*O+h,I=l+T-r;} |
|
|
Nach oben |
|
|
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
Powered by phpBB © 2001, 2005 phpBB Group Deutsche Übersetzung von phpBB.de
|