ANSI C na html

0

Witam serdecznie.

Dostałem projekt, który przyprawił mnie o ból głowy a mianowicie muszę napisać program w języku C, który przekształci plik zawierający kod źródłowy programu w języku C (zakładamy użycie standardu ANSI C) na plik HTML z kolorowaniem składni i opcjonalnym numerowaniem wierszy. Program powinien umożliwiać kolorowanie grupami kolorów następujących składników kodu źródłowego: słów kluczowych języka C, dyrektyw preprocesora, nazw funkcji bibliotecznych (z bibliotek: stdio, stdlib, string, ctype) oraz użytkownika, nazw zmiennych i stałych oraz typów danych użytkownika. Pozostałe elementy, tzn. łańcuchy znaków, liczby, komentarze itp.

Bardzo proszę o pomoc bo nawet nie mam pojęcia od czego zacząć(jestem początkującym programistą)

Z góry dziękuję.

1

Skoro C to proponuje zaprzyjaźnić się ze strstr() bo regexpów niestety nie masz.
0. Numerowanie wierszy jest trywialne

  1. Dyrektywy preprocesora zaczynają się od # a kończą znakiem nowej linii. Więc wszystko co tak wgląda kolorujesz
  2. Słowa kluczowe musisz gdzieś stablicować i znów, szukasz słowa w tekście i kolorujesz
  3. Funkcje biblioteczne jw, funkcje użytkownika musisz najpierw wyszukać, tutaj bez regexpów będzie bieda
  4. Nazwy zmiennych i stałych znów będzie trochę ciężko, bo wyszukać miejsce deklaracji zmiennej jest łatwo, ale potem wyszukać te wystąpienia w kodzie już gorzej bo musisz brać pod uwagę kolejność malowania (np. nazwa zmiennej w stringu nie będzie kolorowana)
  5. Typy danych podobnie, szukasz nazw struktur i klas a potem ich szukasz w programie
  6. Z komentarzami znów będzie problem bez regexpów.

Jesteś pewien że musisz to napisać w czystym C bez żadnych bibliotek?

1

@Shalom: parser napisany w ten sposób wymięknie w 9 na 10 przypadkach.

Żeby zrobić to naprawdę porządnie musiałbyś napisać nie parser, a generator parserów bottom-up. Nie jest to zadanie trywialne i raczej nie o to chodzi. Natomiast parser top-down, np. recursive-descent można napisać z palca i jest to zadanie jak najbardziej wykonalne.
Prosty parser tego typu jest nawet na wikipedii: http://en.wikipedia.org/wiki/Recursive_descent_parser
Kilka parserów języka C napisanych w C masz tutaj: http://stackoverflow.com/questions/1808958/recursive-descent-parser-for-c

1

Jeśli zewnętrzne biblioteki wchodzą w grę, to flex, bison, pcre …

parser napisany w ten sposób wymięknie w 9 na 10 przypadkach.
Kolorowanie nie musi wcale wymagać 100% poprawnego parsera, wystarczy że efekt wizualny będzie ten sam :-)
Co innego gdy piszemy parser celem podpowiadania składni…

0

Dziekuję wszystkim za odpowiedzi. PRzemysle temat i w poniedziałek napiszę co i jak.

0

Oto zalążek

 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char usage[] = "Uzywamy:\n"
               "      c2html [nazwa pliku .C] [nazwa pliku html] [flagi]\n"
               "      Flagi:\n"
               "          -n    Dodawnianie numerowanie wierszy do pliku html.\n";
               
int main( int numArgs, char *argList[] )
{
  FILE *ifp; /*Plik wejsciowy w jezyku C*/
  FILE *ofp; /*Plik wyjsciowy w html*/
  char c;
  char number = 0; /*Numerowanie linii? 0 = Nie 1 = Tak , domyslnie ustawione na 0 */
  int i = 1; /*Licznik potrzebny do numerowania linii*/
  
  if( numArgs < 3 )
  {
    fprintf( stderr, "%s\n", usage );
    return 1;
  }
  
  if( numArgs > 3 && !strcmp( argList[3], "-n" ) )
  {
    number = 1;
  }
  else
  {
    number = 0; /*Przydatne przy nadmiarowosci*/
  }
  
  if( (ifp = fopen( argList[1], "r" ) ) == NULL )
  {
    fprintf( stderr, "Blad: Nie moge otworzyc %s. Przerywam!\n", argList[1] );
    return 1;
  }
  
  if( (ofp = fopen( argList[2], "w" ) ) == NULL )
  {
    fprintf( stderr, "Blad: Nie moge zapisac %s. Przerywam!\n", argList[2] );
    return 1;
  }
  /*Naglowki otwierajace dokument html*/
  fprintf( ofp, "<!--Program stworzyli placek1 i placek2\n--!>\n<html>\n<head>\n<title>%s</title>\n</head>\n<body>\n

\n", argList[1] );

/Jezeli wlaczone numerowanie linii, zacznij numerowac linie/
if( number )
{
fprintf( ofp, "%i: ", i );
i++;
}

while( (c = fgetc( ifp ) ) != EOF )
{
/Znaki do zmiany w standardzie HTML ISO-8859-1/
switch( c )
{
case '"':
fprintf( ofp, """ );
break;
case ''':
fprintf( ofp, "'" );
break;
case '&':
fprintf( ofp, "&" );
break;
case '<':
fprintf( ofp, "<" );
break;
case '>':
fprintf( ofp, ">" );
break;
case '\n':
{
if( number )
{
fprintf( ofp, "
\n%i: ", i++ ); /Jezeli numerujemy wiersze w tym miejscu
zapamietujemy bierzacy numer!
/
while( ( c = fgetc( ifp ) ) == ' ' )
{
fprintf( ofp, " " ); /Tworzenie spacji za pomoca &nbsp's, w przeciwnym wypadku przegladarka je usunie/
}
ungetc( c, ifp ); /Zwraca ostatni znak zeby czytanie bylo szybsze/
}
else
{
fprintf( ofp, "
\n" );
while( ( c = fgetc( ifp ) ) == ' ' )
{
fprintf( ofp, " " ); /To samo co wyzej tylko w opcji bez numerowania wierszy/
}
ungetc( c, ifp );
}
break;
}
default:
fprintf( ofp, "%c", c );
break;
}
}

/Znaki konczace dokument html/
fprintf( ofp, "

\n</body>\n</html>\n" );
  
  /*Zamykanie plikow (wejsciowy i wyjsciowy)*/
  fclose( ofp );
  fclose( ifp );
  
  return 0;
}

I problem Otoż zawartość pliku html jest jakaś dziwna. Są niby te wszystkie heady itd, ale w linijkach pomiedzy wywala mi jakieś dziwne znaki. Ktoś podpowie dlaczego?

0

W załączniku cały kod.

0

Eh człowieka to czasem ogłupi byle co :D

Przy uruchamianiu na ubuntu dawałem:

./c2html test test1 -n

zamiast

./c2html test.c test1.html -n

i stąd takie dziwne znaczki. Teraz pytanie do was jak się zabrać do tych podpunktów:

Program ma również przeprowadzać uproszczoną kontrolę poprawności
kodu, w skład której wchodzi:
• sprawdzenie kompletności bloków "{...}",
• sprawdzenie kończenia linii średnikiem (zwróć uwagę, że nie każda linia musi się kończyć
średnikiem - uwzględnij wyjątki)

0

sprawdzenie kompletności bloków "{...}"

Najprościej jest zrobić sobie zmienną pomocniczą i po wykryciu, że np.w tym momencie zaczyna się funkcja, po prostu ją inkrementować gdy napotka {, a dekrementować gdy trafi na }; gdy odnajdziemy deklarację następnej funkcji i zmienna będzie różna od zera lub w którymś momencie będzie mniejsza od zera, gdzieś są źle ustawione nawiasy.
Btw, porozdzielaj ten kod na funkcje...

0

Pomysł ciekawy, a jak mniej więcej by to wyglądało w implementacji bo nie bardzo wiem jak zacząć?

0

Najłatwiej, jakbyś miał kod przerobiony na poszczególne tokeny, np.

int main()
{
 for (int i=0; i<10; i++) ;
}

Miałbyś wtedy coś w stylu:

identyfikator -> int
identyfikator -> main
nawias otwierający -> (
nawias zamykający -> )
początek bloku -> {
słowo kluczowe `for` -> for
nawias otwierający -> (
identyfikator -> int
identyfikator -> i
znak równości -> =
liczba -> 0

(i tak dalej)
Potem tylko idziesz po kolei po każdym tokenie i sprawdzasz czy jest on równy początek bloku czy koniec bloku i odpowiednio modyfikujesz zmienną.
Funkcję możesz sprawdzić np.w taki sposób:

1.Pierwszy token to typ*
2.Drugi token to identyfikator określający nazwę funkcji
3.Nawias otwierający
4.Parametry funkcji
5.Nawias zamykający
6.Początek bloku

* - typ to niekoniecznie pojedyncze słowo, np.`void*` to także typ
0

Rozumiem no to znowu znikam na tydzień albo dłużej i zobaczymy co z tego wyniknie :D

0

Wymyśliłem coś prostszego. Wczytuje plik i sprawdzam ile jest wystąpień klamer { i }. Jeśli jest otwierająca to daje jakąś zmienna + 1, a jeżeli jest klamra } to zmienna - 1. Po prostu jeżeli jest ich parzysta ilość to jest ok, a jeżeli nie to mogłoby to podświetlać w którym miejscu znalazło nieparzystą klamrę. Problem w tym że nie wiem za bardzo jak się za to wsiąć

0

Człowieku to program demonstracyjny na projekt. Kto ci da tyle tych klamer normalny?

0

Skoro pomysł jest zły to podaj lepszy

0

Daliśmy ci już lepszy pomysł - trzeba napisać normalny parser albo skorzystać z generatora parserów. Projekt też trochę z d**y, bo powinien być właśnie z przedmiotu dotyczącego parserów czy kompilatorów.
Możesz spojrzeć też na http://www.gnu.org/software/src-highlite/ - kilka innych aplikacji również korzysta z jego składni i uniwersalnego parsera.

W każdym razie, porządne wykonanie tego projektu to na pewno nie jest prosta rzecz. Jeżeli chcesz liznąć trochę teorii albo poczytać dobrą książkę na ten temat to mogę polecić "książkę ze smokiem na okładce", czyli "Compilers: Principles, Techniques, and Tools". Połowa z niej może się bezpośrednio przydać w tym projekcie.

0

W pętli „zjadaj” kolejno znaki wejściowe. Przechowuj stan maszyny określający, wewnątrz jakiego tokena się znajdujesz (identyfikatora, komentarza, stringa, liczby itd.) W momencie gdy natrafiasz na znak oznaczający koniec danego tokena, wypluwasz htmlowego taga i wracasz do stanu początkowego (start nowego tokena).

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