Zum Inhalt springen

IF ELSE ENDIF - komm einfach nicht weiter


paule22

Empfohlene Beiträge

Hi C coders 4,

I try to program a interpreter and have the problem of a IF - ELSE - ENDIF

statement.

here is the pseudo code:

Note:

if_stmt = 0 stands for execute flag for the following IF statement, 0 for

ELSE - not true.

stmt[pos] is a variable that store, if the code block is true for EXEC -

YES or NO

code in two brackets [ ] are code that should be handle by the program if a

token like

ENDIF is reading from the file.

IF <var1> = 1

  if_pos++

  stmt[if_pos] = YES_EXEC

  if_stmt = 0

  IF <var2> = 1

  if_pos++

  stmt[if_pos] = YES_EXEC

   ELSE

stmt[if_pos] = NO_EXEC

if_stmt = 1

// here comes a second problem:

// IF var2 not 1

// than if_stmt must be true, also

// if_stmt = 0

IF <var3> = 1

if_pos++;

stmt[if_pos] = YES_EXEC

if_stmt = 0

ELSE

stmt[if_pos} = NO_EXEC

if_stmt = 1

ENDIF

[ if_pos-- ]

ENDIF

[ if_pos-- ]

ELSE

stmt[if_pos] = NO_EXEC

if_stmt = 1

ENDIF

[ if_pos-- ]

// -------------------------------------------------------------------------

-----

// no more if statement - set the execution flag to true: 0

// -------------------------------------------------------------------------

-----

if (if_pos == 0)

{

if_stmt = 0;

}

next stage of pharse:

// ---------------------------------------------------------------

// here comes code that can be appear in a IF

// statement block or outside ...

// ---------------------------------------------------------------

switch (get_token())

{

case DT_PRINT:

{

handle_string();

if (if_stmt == 0)

Memo->Lines->Add( parsed_token_string );

else if (if_stmt == 1) { /* do nothing - no output */ }

}

break;

}

here is the handle procedure that should handle the IF block:

(raw code) please correct it ...

// global values ...

#define YES_EXEC 0

#define NO_EXEC 1

int if_pos = 0;

int stmt[2048];

int handle_procedure(void)

{

int count_if_statments = 0;

for (;;)

{

switch (get_token())

{

case DT_PRINT:

{

handle_string();

if (if_stmt == 0)

Memo->Lines->Add( parsed_token_string );

}

break;

case DT_ENDIF:

{

if (count_if_statments == 0)

return fatal("ENDIF without IF-Block start");

if_pos--;

count_if_statments--;

// no more IF blocks, enable exec

if (if_pos == 0)

{

if_stmt = 0;

}

}

break;

case DT_ELSE:

{

// here comes the problem ...

// what is, when the previous IF check is false ??

// and vice versa true ??

// if it true, than must the next IF in the ELSE block

// false, too

// Also so:

//

// var1 = 2

// var2 = 4

// IF <var1> = 3

// ELSE

// IF <var2> = 4

// ELSE

// ENDIF

// ENDIF and so on

//

if (stmt[if_pos] == YES_EXEC)

if_stmt = 1; else

if_stmt = 0;

}

break;

case DT_IF:

{

count_if_statements++;

if_pos++;

handle_if_statment();

}

break;

case DT_RETURN: return RET_OK; // to leave the for-loop

break;

}

}

}

any help are very welcome

psst: please tell me your money account to sent you 5 Dollars

for solving this problem :-)

okay, joke, but not impossible :-)

If you would like to have the working code for "get_token()" -- let me know.

thanks forward

Paul

okay, here comes the get_token() code, to make it easier to

following the example code ...

FILE *input_file;

AnsiString token_buffer;

#define ENDFILE -1

#define IDENTIFIER 1

#define NUMBER 2

#define POINT_TOKEN 100

#define EQUALSIGN 124

#define MINUS 125

#define ILLEGAL 140

#define DT_PRINT 1000

#define DT_IF 1001

#define DT_ENDIF 1002

#define DT_ELSE 1003

// -------------------------------------------------------------------------

--

// get one charachter an handle comments in a dbase file ...

// -------------------------------------------------------------------------

--

int skip_white_space(void)

{

AnsiString buffer;

char c;

char inside;

c = fgetc(input_file);

for (;;) {

int cplus_comment;

switch ©

{

case '/':

c = fgetc(input_file);

// --------------------------------------------

// at back of a comment can be a

// nummeric operator ...

// --------------------------------------------

if (c >= '0' && c <= '9' || c == '(' || c == ' ' || c == '\n') {

ungetc(c,input_file);

return '/';

} else

if (c != '*' && c != '/') {

AnsiString str;

str = "undefined char `/";

str += c;

str += "' found";

return fatal(str);

}

cplus_comment = (c == '/');

c = fgetc(input_file);

inside = 1;

while (inside)

{

if (!cplus_comment && c == '*')

{

while (c == '*')

c = fgetc(input_file);

if (c == '/')

{

inside = 0;

c = fgetc(input_file);

}

}

else if (c == '\n')

{

line_no++;

if (cplus_comment)

inside = 0;

c = fgetc(input_file);

}

else if (c == EOF)

return fatal("comment line not correctly end.");

else

c = fgetc(input_file);

}

break;

case '\n': line_no++;

case ' ':

case '\t':

case '\f':

c = fgetc(input_file);

break;

default:

return ©;

}

}

}

int lex(void)

{

char buffer[5];

int pos = 0;

int c;

c = skip_white_space();

switch ©

{

case EOF: { return (ENDFILE); }

break;

case '.': return POINT_TOKEN;

case '?': return DT_PRINT;

case 'A': case 'B': case 'C': case 'D': case 'E':

case 'F': case 'G': case 'H': case 'I': case 'J':

case 'K': case 'L': case 'M': case 'N': case 'O':

case 'P': case 'Q': case 'R': case 'S': case 'T':

case 'U': case 'V': case 'W': case 'X': case 'Y':

case 'Z':

case 'a': case 'b': case 'c': case 'd': case 'e':

case 'f': case 'g': case 'h': case 'i': case 'j':

case 'k': case 'l': case 'm': case 'n': case 'o':

case 'p': case 'q': case 'r': case 's': case 't':

case 'u': case 'v': case 'w': case 'x': case 'y':

case 'z':

case '_':

{

sprintf(buffer,"%c",c);

token_buffer = buffer;

while (isalnum© || c == '_')

{

if (pos) {

sprintf(buffer,"%c",c);

token_buffer += buffer;

}

c = fgetc(input_file);

pos++;

}

ungetc(c, input_file);

return (IDENTIFIER);

}

break;

case '0': case '1': case '2': case '3': case '4':

case '5': case '6': case '7': case '8': case '9':

{

int token_val = 0;

token_value = 0;

while (isdigit© || c == '.')

{

if (c == '.')

{

token_val = 0;

c = fgetc(input_file);

while (isdigit©)

{

token_val = token_val*10 + c - '0';

c = fgetc(input_file);

}

goto n2;

}

else {

token_value = token_value*10 + c - '0';

c = fgetc(input_file);

}

}

n2:

AnsiString str;

str = token_value;

str += ",";

str += token_val;

double wert = StrToFloat(str);

token_value = wert;

ungetc(c, input_file);

return (NUMBER);

}

break;

case '=': { return EQUALSIGN; } break;

case '-': { return '-'; } break;

case '*': { return '*'; } break;

case '/': { return '/'; } break;

case ';': { return ';'; } break;

case '(': { return '('; } break;

case ')': { return ')'; } break;

case '>': { return '>'; } break;

case '<': { return '<'; } break;

default: { return c; }

}

return ILLEGAL;

}

struct DT_variables {

char *name;

int id;

} dt_vars[] = {

"if", DT_IF,

"endif", DT_ENDIF,

"else", DT_ELSE,

0,0

};

// -------------------------------------------------------------------------

---

// get token, and return an id number of it ...

// -------------------------------------------------------------------------

---

int get_token(void)

{

int code;

for (;;)

{

code = lex();

if (code == IDENTIFIER || code == DT_PRINT)

{

if (code == DT_PRINT)

return DT_PRINT;

int c;

for (c = 0; c < MAX_TOKEN; c++)

{

if (LowerCase(token_buffer) == dt_vars[c].name)

return dt_vars[c].id;

} return DT_USERDEF;

} else

if (code == NUMBER) { return fatal("expected a string-Token here."); }

else

if (code == ENDFILE) { return ENDFILE; }

}

return RET_OK;

}

hoffentlich kann sich da einer reinwusseln ?

thanks for help

Paul

Link zu diesem Kommentar
Auf anderen Seiten teilen

From my understanding he want's to write a parser which is able to parse the code fragment (IF - ELSE - ENDIF) mentioned above. Which obviously does not work as expected ;). To be honest I'm not keen on going through the code but I can give an recommendation for an optional (and for Unix users straight forward) implementation: Use lex and yacc (or flex and bision) especially if you plan to extend your program to understand more keywords. lex/flex is a tool for generating scanners based on a rule file where a rule is a combination of and regular expression and some C/C++ code. yacc/bison are used to generate parsers. Both tools generate C code. For simple tasks the use of bison should be sufficient without any need for flex. I think one of the problems in your code is that there is no destinction between code which belongs to the "IF" statement and code which is evaluated within the "IF" statement. Your parser does not no when to start with the calculation of the result of the "IF". This is the reason why most language use something like "then" or ";" to indicate the end of the comparison and easy to fix:

IF <statement> THEN

[... do something ]

ELSE

[... do something else ]

ENDIF

Nic

PS:

Answer in english because initial question was also in english.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Without a correct syntax the compiler don´t wanna run it.

IF <var3> = 1 // should this be a template? Where´s the Macro for IF?

stmt[if_pos] = YES_EXEC // as Nic told-> no ; in sight

[ if_pos-- ] // a strange kind of Field-Index without array and ;?

return fatal("ENDIF without IF-Block start"); // is fatal an own String-Generator? Why not returning the String itself?

if (stmt[if_pos] == YES_EXEC)

if_stmt = 1; else // no good style

if_stmt = 0;

handle_if_statment(); // one line before you use the expression if_statement with 'e'-> My advice: Don´t use similar names if possible

Except of these small hints I would say your code is a good example why people get frightened of going into C.

I think it´s nearly impossible to draw the teeth without knowing which one hurts or not... we could choose all - but then there´s nothing to byte any more. Where´s the detailed question?

Is this some strange kind of test?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Original geschrieben von gajUli

Nope.

Eine "initial question" gab es gar nicht, und am Ende stand noch dazu ein deutscher Satz.

Stimmt, da hast Du recht. Im Ursprungsposting wurde keine Frage gestellt. So gesehen koennen wir eigentlich nur raten worum es geht (sofern die Frage nicht gestellt/praezisiert wird). Den deutschsprachigen Satz am Ende habe ich natuerlich auch gesehen. Allerdings hoffe ich, dass es einen triftigen Grund fuer die Wahl der Sprache gibt (und das es nicht blosse Faulheit war, den Beitrag ins deutsche zu uebersetzen), daher die Antwort auf englisch.

Nic

Link zu diesem Kommentar
Auf anderen Seiten teilen

moin,

blose faulheit, okay, ja habt ja recht.

das gleiche posting hatte ich in einen englischen forum gepostet und wollte mir die mühe ersparren sorry leute.

ist doch trotzdem mal ne abwechslung im tristen alltag - oder ?

was Linux/Unix anbelangt - das Ding mit Lex/Yacc und Bison - hab ich mal probiert auf DOS, klappt auch soweit recht gut mit den GNU GCC Tools, allerdings verwende ich den Borland CBuilder und da kommt es zu komplikationen beim code übersetzten.

Wäre vielleicht mal ne interessante Aufgabe für jemanden, diese teile - also Lex/Bison für Borland produkte gangfähig zu machen - würde mich auch erkenntlich zeigen :-)

also wie gesagt, ich versuche einen interpreter zu schreiben, der IF ELSE ENDIF auswerten kann. allerdings scheitert die ganze sache nicht am eigentlichen auslesen von IF ELSE ENDIF, sondern darin, dass, wenn ein ELSE oder ein ENDIF innerhalb eines IF Blocks vorkommt.

dann verwende ich nämlich folgenden Code:

switch(get_token())

{

case DT_ENDIF:

if (!if_rec) fatal("ENDIF ohne IF-Bedingung nicht erlaubt.");

if_rec--;

if (!if_rec) if_stmt = 0;

else {

for (int pos = 0; pos < if_rec; pos++)

if (exec_if_stmt[pos] == YES_EXEC) if_stmt = 0;

}

break;

case DT_ELSE:

if (if_rec > 0)

if (exec_if_stmt[if_rec] == YES_EXEC) if_stmt = 0; else if_stmt = 1;

break;

case DT_IF:

if_rec++

handle_if_statment();

break;

}

und nun der code zum parsen der IF anweisung ...

handle_if_statement()

{

AnsiString saved_token;

switch (get_token())

{

case DT_USERDEF:

{

saved_token = AnsiLowerCase(token_buffer);

AnsiString str;

str = "procedure_local_";

str += saved_token;

if (can_exec && !if_stmt)

{

if (!(var_ptr = get_variable(str)))

fatal("IF-Variable ist nicht definiert/bekannt.");

int code = lex();

if (code != EQUALSIGN)

fatal("Gleichheitszeichen '=' hier erwartet.");

// ------------------------

// IF <variable> = EXPR ...

// ------------------------

if (var_ptr->type == VARTYPE_VALUE)

{

double wert1 = var_ptr->var_value;

double wert2 = handle_expr(EP_AND);

if (wert1 == wert2)

{

ShowMessage("wert ist gleich");

exec_if_stmt[if_rec] = YES_EXEC;

if_stmt = 0;

return RET_OK;

}

else {

ShowMessage("wert ist ungleich nicht gleich nix gleich");

exec_if_stmt[if_rec] = NO_EXEC;

if_stmt = 1;

return RET_OK;

}

}

}

else {

int code = lex();

if (code != EQUALSIGN)

fatal("Gleichheitszeichen '=' hier erwartet.");

next_t:

double wert2 = handle_expr(EP_AND);

if_stmt = 1;

exec_if_stmt[if_rec] = NO_EXEC;

return RET_OK;

}

}

break;

default:

fatal("Benutzerdefiniertes token hier erwartet.");

break;

}

}

der code funktioniert einwandfrei - auch die Auswertung des IF ELSE ENDIF Blocks, sofern es immer nur einer is.

Aber was is, wenn mehrere IF-ELSE-ENDIF blöcke geschachtelt werden ??

dafür brauche ich ne Lösung.

so das wars eigentlich.

Paul

Link zu diesem Kommentar
Auf anderen Seiten teilen

jo danke crush,

die IFs zähle ich mit.

hab mal daran gedacht ne struktur mit in spiel zu bringen

etwa so:

#define NO_EXEC 1

#define YES_EXEC 0

struct if_stmt_block

{

char yes;

char no;

}

struc if_stmt_block stmt[2048];

wenn .yes gesetzt ist mit YES_EXEC und .no = NO_EXEC, dann normalen IF block abarbeiten ansonsten (.yes = NO_EXEC und .no = YES_EXEC - dann ELSE block abarbeiten)

dann schaut in etwa der pseudo code so aus, der abgearbeitet werden muss - irgendwie - halt mal ne neue idee:

if_rec = 0;

IF <var1> # 2

     // if zählen ...

     if_rec++;

     // dieser Pseudo code muss natürlich erstmal auf korrektheit

     // überprüft werden - siehe handle_if_statemnt()

     //

     if (var1 ist ungleich 2)

     dann

        stmt[0].yes = YES_EXEC;

        stmt[0].no = NO_EXEC;     // ELSE block nicht beachten

     ansonsten

        stmt[0].yes = NO_EXEC;

        stmt[0].no = YES_EXEC;     // ELSE block abarbeiten

     end

     IF <var2> = 2

     if_rec++;

     // hier muss überprüft werden, ob der momentane CodeBlock

     // abgearbeitet werden kann - siehe .yes .no

         stmt[1].yes = YES_EXEC;

         stmt[1].no = NO_EXEC;

     ENDIF

     // nach jedem ENDIF, if_rec runterschrauben

     if_rec--;

     // hier muss auch/nochmals überprüft werden, ob der momentane CodeBlock

     // abgearbeitet werden kann - könnte ja sein, das hinter dem

     // ENDIF weitere Anweisungen stehen

ENDIF

if_rec--;

// ab hier gehts dann normal weiter

if (if_rec == 0) .....

muss halt nur noch eine entsprechende routine for jedem DT_IF und DT_ENDIF und natürlich auch dT_ELSE, die überprüft, ob die bedingungen zutreffen.

dann wäre eigentlich das Problem gelöst ?

denke ich jedenfalls.

in der vorliegenden Pseudo form können IF's maximal 2047 mal verschachtelt sein - man könnte des auch dynamisch machen um auf unbegrenzt (gut 2 Millarden etwa :) hochschrauben kann.

Aber der übersichtlichkeit halber hab ich des mal statisch gelassen.

jede idea des händlings ist willkommen !!!

vielleicht is des auch ne anregung für jemand anderen, der das gleiche Problemchen hat ...

Paul

Link zu diesem Kommentar
Auf anderen Seiten teilen

jo danke für dein Hinweis.

das Problem was bei diesen Interpreter ist, die Zeichenketten werden linear abgearbeitet - wie eine BATCH datei.

Ansonsten müsste ich mir was anderes überlegen - sowas wie ne STACK machine oder so was in der art ?

erst den gesammten code einlesen in nen string und dann den string (Stack) abarbeiten.

Ist das net doppelt gemoppelt ?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...