Rozpoznawanie składni

0

Program ma za zadanie rozpoznawać funkcje i wypisywać gdzie jest prototyp definicja i wywołania.
To są dwa moduły :
Idzie mi dość średnio bo jeśli podam kod źródłowy alex.c do analizowania to nie widzi pierwszego nawiasu otwierającego i próbuje sie odwołać do pustego stosu.
W innych plikach sytuacja wygląda lepiej ale też nie zawsze wypisuje wszystkie.
Jeśli ktoś mógł by pomóc w znalezieniu błędu był bym wdzięczny.

alex.c

#include "alex.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

static int  ln= 0;
static char ident[256];
static FILE *ci= NULL;

void    alex_init4file( FILE *in ) {
   ln= 0;
   ci= in;
}

lexem_t alex_nextLexem( void ) {
  int c;
  while( (c = fgetc(ci)) != EOF ) {
    if( isspace( c ) )
        continue;
		
    else if( c == '\n' ){
        ln++;
		continue;
		}
    else if( c == '(' )
        return OPEPAR;
		
    else if( c == ')' )
      return CLOPAR;
	  
    else if( c == '{' )
        return OPEBRA;
		
    else if( c == '}' )
        return CLOBRA;
		
    else if( isalpha( c ) ) {
		int i= 1;
		ident[0] = c;
		while( isalnum( c = fgetc(ci) ) || c == '_' )
		ident[i++] = c;
		ident[i] = '\0';
		return isKeyword(ident) ? OTHER : IDENT; }
		
	else if( c == '"' ) {
        while( (c = fgetc(ci)) != EOF && c != '"' ) 
    return c==EOF ? EOFILE : OTHER; 
    } 
	else if( c == '\'' ) {
        while( (c = fgetc(ci)) != EOF && c != '\'' ) 
    return c==EOF ? EOFILE : OTHER; 
    } 	
	else if( c == '/' ) {
		if ( (c = fgetc(ci)) == '*' ) {
			while ((c = fgetc(ci)) != '*');
			while ((c = fgetc(ci)) != '/');
			continue; 
		}
		continue;
	} 
	if( isdigit( c ) || c == '.' ) {
      continue;
    } 
	else {
		return OTHER;
    }
} 

  return EOFILE;
}

char *  alex_ident( void ) {
   return ident;
}

int     alex_getLN() {
        return ln;
}

int isKeyword(char * napis)
{
	char buf[BUFSIZE];
	FILE *in = fopen(FKEYWORD,"r");
	if (in == NULL) 
	{
		fprintf(stderr,"Nie można otworzyć pliku");
		exit(EXIT_FAILURE);
	}
	
	while( fgets( buf, BUFSIZE, in ) != NULL ) {
    char *wskaznik;  
		if( (wskaznik = strstr( buf, napis )) != NULL ) {
			char * wk = wskaznik + strlen(napis);
			char * wp = buf == wskaznik ? wk : wskaznik - 1;		  
			if(isalpha(*wp) == 0 && isalpha(*wk) == 0){
				fclose(in);
				return 1;
			}	
                 
		}
	}
	fclose(in);
	return 0;
}

paser.c

#include <stdio.h>
#include <stdlib.h> /*exit - ale exit trzeba kiedyś usunąć i nie będzie to potrzebne*/
#include "alex.h"       /*analizator leksykalny*/
#include "fun_stack.h"  /*stos funkcji*/
#include "store.h"
#include "parser.h"

#define MAXINDENTLENGHT 256     /*maks długość identyfikatora*/

void
analizatorSkladni (char *inpname)
{                               /*przetwarza plik inpname*/

  FILE *in = fopen (inpname, "r");

  int nbra = 0;   /*bilans nawiasów klamrowych {}*/
  int npar = 0;   /*bilans nawiasów zwykłych ()*/

  alex_init4file (in);          /*ustaw analizator leksykalny, aby czytał in*/

  lexem_t lex;

  lex = alex_nextLexem ();      /*pobierz następny leksem*/
  while (lex != EOFILE) {
    switch (lex) {
    case IDENT:{
        char *iname = alex_ident ();   /*zapamiętaj identyfikator i patrz co dalej*/
        lexem_t nlex = alex_nextLexem ();
        if (nlex == OPEPAR) {   /*nawias otwierający - to zapewne funkcja*/
          npar++;
          put_on_fun_stack (npar, iname);       /*odłóż na stos funkcji*/
                                                /*stos f. jest niezbędny, aby poprawnie obsłużyć sytuacje typu*/
                                                /*f1( 5, f2( a ), f3( b ) )*/
        }
        else {                  /*nie nawias, czyli nie funkcja*/
          lex = nlex;
          continue;
        }
      }
      break;
    case OPEPAR:
      npar++;
      break;
    case CLOPAR:{              /*zamykający nawias - to może być koniec prototypu, nagłówka albo wywołania*/
        if (top_of_funstack () == npar) {       /*sprawdzamy, czy liczba nawiasów bilansuje się z wierzchołkiem stosu funkcji*/
                                                /*jeśli tak, to właśnie wczytany nawias jest domknięciem nawiasu otwartego*/
                                                /*za identyfikatorem znajdującym się na wierzchołku stosu*/
          lexem_t nlex = alex_nextLexem ();     /*bierzemy nast leksem*/
          if (nlex == OPEBRA) {  /*nast. leksem to klamra a więc mamy do czynienia z def. funkcji*/
            store_add_def (get_from_fun_stack (), alex_getLN (), inpname);
			nbra++;
			}
          else if (nbra == 0)   /*nast. leksem to nie { i jesteśmy poza blokami - to musi być prototyp*/
            store_add_proto (get_from_fun_stack (), alex_getLN (), inpname);
          else                  /*nast. leksem to nie { i jesteśmy wewnątrz bloku - to zapewne wywołanie*/
            store_add_call (get_from_fun_stack (), alex_getLN (), inpname);
        }
        npar--;
      }
      break;
    case OPEBRA:
      nbra++;
      break;
    case CLOBRA:
      nbra--;
      break;
    case ERROR:{
        fprintf (stderr, "\nBUUUUUUUUUUUUUUUUUUUUUU!\n"
                 "W pliku %s (linia %d) są błędy składni.\n"
                 "Kończę!\n\n", inpname, alex_getLN ());
        exit (1);              
      }
      break;
    default:
      break;
    }
    lex = alex_nextLexem ();
  }
}
1

Tak na szybko:

lexem_t alex_nextLexem( void ) 
{
	...
	
	while( (c = fgetc(ci)) != EOF ) 
	{
		...
		
		else if( isalpha( c ) ) 
		{
			...
			while( isalnum( c = fgetc(ci) ) || c == '_' ) ident[i++] = c;
			
			...
			return ... 
		}
		
	...
}

Jeśli po nazwie funkcji od razu będzie nawias otwierający, pętla while zatrzyma się, gdy c == '(' . Problem w tym, że z tym nawiasem nic dalej nie robisz, pomijasz go, jakby był białym znakiem. Użyj ungetc.

int isKeyword(char * napis)
{
    FILE *in = fopen(FKEYWORD,"r");
	...
	
}

Uuu panie! Nie sądzisz, że sensowniej jest wczytać na początku programu słowa kluczowe do jakiejś tabeli niż co chwila otwierać strumień?

p.s. debugger Twoim przyjacielem ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1