[flex] FILE* <-> char*

Du hast bei deinem CreatePipe die Größe des Buffers vergessen. :p

Hm, dann hab ich doch noch einiges nicht verstanden, schätze ich.

Warum muss die Pipe dubliziert werden?


Inzwischen habe ich ein bisschen rumgesucht.
Ich habe eine Funktion gefunden, die mir scheinbar stdin zu einer Pipe (Handle) konvertiert.
GetStdHandle(STD_INPUT_HANDLE)

Code:
DWORD ignore;
HANDLE fp;
fp = GetStdHandle(STD_INPUT_HANDLE);
WriteFile(fp,"abcdef\n",7,&ignore,NULL);
CloseHandle(fp); 
yylex();
Leider gibts da n Fehler.
"input in flex scanner failed"

Wenn ich das "CloseHandle" weglasse, kommt der Fehler nicht, aber der Input wird nicht geschlossen, weil kein EOF kommt.

Darüberhinaus, scheint die Pipe leer zu sein. :(

Ich habe fp mal mit GetStdHandle(STD_OUTPUT_HANDLE) belegt.
Die erwartete Ausgabe auf der Konsole kommt auch.


Wenn ich deinen Code nehme und darunter WriteFile benutze, komme ich zum gleichen Ergebnis, denke ich.
Lex wartet auf eine Eingabe.

/edit
Okay, ich glaub, ich habe jetzt verstanden, warum Lex abgeschmiert ist, wenn ich das Handle geschlossen habe.
Zu einer Pipe gehören 2 Handles. Das eine lauscht, das andere spricht... zumindest in meinem Beispiel.
Ich muss das lauschende mit stdin belegen und das sprechende schließen, um mein EOF zu bekommen.
Gut... aber das Hauptproblem, dass stdin nicht gefüllt wird, ist leider nicht gelöst.

/edit2
Ich verstehe es nicht. :(
Die Pipe selbst scheint gut zu funktionieren.
Code:
int main ()
{
  DWORD ignore;
  HANDLE fp_r, fp_w;
  CreatePipe(&fp_r, &fp_w, NULL, 1000);
  
  WriteFile(fp_w,"abcdef\n",7,&ignore,NULL);
  CloseHandle(fp_w);
  
  char buffer[7];
  ReadFile(fp_r,buffer,7,&ignore,NULL);
  fwrite(buffer,ignore,1,stdout);

  return 0;
}
.. das klappt super.
Auch wenn ich nun versuche fp_r stdin zuzuweisen, kann ich die Pipe auf diese Weise noch auslesen.
Aber das ganze hat keinen Effekt auf stdin.

Wer kein (f)lex hat und dennoch an dem Thema interessiert ist, müsste auch einfach versuchen können, ob getchar() was ausspuckt oder auf eine Eingabe wartet (wenns , muss man nicht warten).

Ich hab inzwischen ein Beispiel gefunden, in dem es jemand geschaff hat, stdin was zu schicken.
Allerdings hat der n neuen Prozess aufgemacht und dessen stdin/out/err mit seinen Pipes belegt (mit nem struct namens STARTUPINFO glaub ich). Habs auch nicht geschafft, das umzubauen.
Hier ist der Link:
http://www.3rd-evolution.de/tkrammer/docs/apipes.html
 
Zuletzt bearbeitet:
mueslirocker hat gesagt.:
Ich habe eine Funktion gefunden, die mir scheinbar stdin zu einer Pipe (Handle) konvertiert.
GetStdHandle(STD_INPUT_HANDLE)
Nee, GetStdHandle gibt nur das Handle für die Standardeingabe zurück. Ein Handle ist eine eindeutige Nummer die zur Identifikation der Ein-/Ausgabe benutzt wird. Z.B. wenn eine Datei geöffnet wird, wird dieser Datei ein Handle zugeteilt und mit Hilfe dieses Handles kann man von der Datei lesen bzw. schreiben usw.

Eine Pipe ist im Grunde nix weiter als ein Puffer (vom Betriebssystem bereitgestellt) mit einer Ein- und Ausgabe (eben wie eine Röhre) bzw. einem Handle für die Ein- und einem für die Ausgabe.

mueslirocker hat gesagt.:
Warum muss die Pipe dubliziert werden?
Die Pipe wird nicht dupliziert, wenn dann nur die Eingabe der Pipe. Und wie gesagt bin ich mir nicht sicher ob das überhaupt gemacht werden muß (ich hab es einfach von dem Beispiel auf MSDN übernommen, aber da ist die Sachlage auch etwas anders).

So. Jetzt hab ich es gerade auch mal ausprobiert und es scheint so, dass das Handle welches durch SetStdHandle gesetzt wird nicht dasselbe ist wie das Handle (bzw. der Dateideskriptor) von dem scanf liest. Ich frage mich wozu SetStdHandle dann gut ist?! Also soweit ich das sehe wird das so unter Windows nix. (Windows Gurus?)

Aber: Definier doch einfach das YY_INPUT macro um. Das scheint mir auch viel einfacher zu sein. ;-)
Code:
#define YY_INPUT(buf,result,max_size) \
    { \
    int c = getchar(); \
    result = (c == EOF) ? YY_NULL : (buf[0] = c, 1); \
    }
Du musst ja nicht von einer Datei lesen. Kannst ja auch einfach von deinem Eingabestring in den Puffer buf kopieren und flex arbeitet dann auf dieser Eingabe. yyin ist dabei völlig egal.
 
Na, da editier ich grad meine neusten Erkenntnisse (die absolut nichts gebracht haben ^^) rein und dann kommt schon ne Antwort.

Der beschriebene Effekt scheint nicht nur nicht auf scanf sondern auch auf getchar zuzutreffen.. wahrscheinlich basiert scanf auf getchar !?

Das Macro umschreiben... ui, böse. :)
Ich werd mich mal dran versuchen.
Aber macht es Sinn, den String in buf zu schreiben?
Ist das nicht ein Zwischenspeicher von lex, in dem immer nur Teilausdrücke stehen?
Ich könnte aber getchar() durch eine andere Methode (die meinen String durchgeht) ersetzen.

Ich melde mich, wenn ich was neues weiß (oder du mir noch einen Rat gegeben hast). :)
Danke für die Hilfe.
So viel Mühe macht sich nicht jeder.


/edit

Okay, ich glaube, es funktioniert jetzt.

Hier nochmal das fertige (Test-)Programm:
Code:
%{

#define YY_INPUT(buf,result,max_size) \
    { \
    int c = getchar2(); \
    result = (c == EOF) ? YY_NULL : (buf[0] = c, 1); \
    }

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

char inputstring[50];
char *cinput;

char getchar2() {
  if (*cinput != '\0')
   return *(cinput++);
  return EOF;
}

%}

%%

.                printf("%s",yytext);
\n               printf("%s",yytext);

%%

int main ()
{
  strcpy(inputstring,"abcdef");
  cinput = inputstring;
  yylex();
}

Nochmal vielen Dank für die Hilfe.
Auch wenns mir diesmal absolut nichts gebracht hat, find ich's schön, dass ich mal was über Pipes gelernt hab. :)
Ich denke, damit ist das Thema erledigt.

... falls nicht, komm ich wieder. :p
 
Zuletzt bearbeitet:
Also YY_INPUT ist ein Makro welches Flex normalerweise benutzt um Daten von yyin zu lesen, in buf zu speichern und dann zu verarbeiten.

Normalerweise wird das auch nicht zeichenweise gemacht, sondern blockweise. Das was ich da gepostet hab war bereits ein Beispiel wie man es anders definieren kann. Man könnte ja evtl. sowas wie
Code:
strncpy(buf, mein_string, max_size);
return (strlen(mein_string) < max_size ? YY_NULL : strlen(mein_string));
machen.

Ich würd sagen, probiers einfach mal aus.
 
Ah, schade.
Hab ich wieder mal was missverstanden.
Da getc(har) gerade nicht funktionierte, dachte ich, dass es sich um das ursprüngliche Macro handelte.

Deinen zweiten Vorschlag verstehe ich nicht so ganz.
Meinst du in der zweiten Zeile result oder return?
Und da fehlt irgendwo noch ein EOF, oder?

Ich hab mir mal das Orginal angeschaut und da folgendes draus gebaut:
Code:
#define YY_GET_C ((*cinput == '\0') ? EOF : *(cinput++))

#define YY_INPUT(buf,result,max_size) \
        { \
        int n; \
        char c; \
        for ( n = 0; n < max_size &&  (c = YY_GET_C) != EOF && c != '\n'; ++n ) \
            buf[n] =  c; \
        if ( c == '\n' ) \
            buf[n++] = c; \
        result = n; \
        }

...

strcpy(inputstring,"abcdef");
cinput = inputstring;
Ich bin mir aber nicht sicher, ob ich das ursprüngliche Macro ganz verstanden habe und entsprechend weiß ich nicht, ob ich einen Fall übersehen habe.
Scheint aber so zu funktionieren...
 
Zuletzt bearbeitet:
Ja, das was ich vorgeschlagen hab, war nur ein (ausbaufähiger) Lösungsansatz.

Ich hatte es mir ungefähr so gedacht:
Code:
%{

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

char *string = "blah blah\n", *pos;

#define YY_INPUT(buf,result,max_size) \
if (*pos != '\0') { \
   int len = strlen(pos); \
   strncpy(buf, pos, max_size); \
   pos += result = (len < max_size) ? len : max_size; \
} else result = YY_NULL; \


%}

%option noyywrap

%%

.           printf("%s",yytext);
\n          printf("%s",yytext);

%%

int main() {
  pos = string;

  yylex();

  return 0;
}

Ansonsten sieht dein Kode gut aus. Wobei ich gerade bemerkt hab das du zeilenweise vorgehst. Aber das macht ja nix ;-)
 
Joa, das zeilenweise Vorgehen hab ich aus dem Orginal übernommen.. stand so im "interaktiven" Teil (für stdin nehm ich mal an).

Sowas ähnliches wie dein Code hab ich erst auch versucht.
Wollte den String so weit wie möglich kopieren.
Aber ich habs nicht hinbekommen, da ich nicht wusste, wie ich die Kopie begrenzen kann, falls max_size überstiegen wird.
Daher bin ich Zeichenweise vorgegangen.
strncpy kenn ich nicht. Aber das scheint die Lösung dafür zu sein, oder?
strncpy(char *a, char *b, int n) <- Sieht für mich so aus, als kopiert die Funktion die ersten n Zeichen (oder wenn b nicht so viele Zeichen hat, halt den ganzen String) von b nach a. Ist das korrekt?
 
mueslirocker hat gesagt.:
strncpy(char *a, char *b, int n) <- Sieht für mich so aus, als kopiert die Funktion die ersten n Zeichen (oder wenn b nicht so viele Zeichen hat, halt den ganzen String) von b nach a. Ist das korrekt?
Ganz genau.

Siehe z.B. http://maconlinux.net/linux-man-pages/de/strncpy.3.htm

Wobei ich gerade sehe, das wenn b weniger als n Zeichen hat, das der Rest des Platzes in a mit Nullen aufgefüllt wird (was ja eigentlich nichts macht, aber unnötig ist - eigentlich).
 
Gut danke.
Ich schätze, dann werde ich dein Macro benutzen (bzw nochmal neu schreiben um was zu lernen. :) ).

Ich denke, dass es nicht schneller geht, zu prüfen, ob der String b kürzer als n ist, als ihn einfach bis zur n-ten Stelle voll zu schreiben... hm, obwohl man das ja auch beim Vollschreiben bemerken könnte.
Naja, jedenfalls ist es nicht kritisch.
 
Zurück