Hi.
Ich möchte einen simplen Kommandozeilenparser mit lex und yacc basteln
aber trotz Lesens diverser (online) Literatur, Manuals und auch
Beispielcode
habe ich wohl einen Knoten im Kopf der mich hindert vorwärts zu kommen.
Ich habe mir 2 Bücher bestellt die hoffentlich heute kommen...
Ich möchte simple Kommandozeilen wie z.B. diese hier parsen und
Variablen setzen und lesen:
set meas dac 0 offset 33<lf>
oder halt
get meas dac 0 offset<lf>
Dazu habe ich folgendes lex file gebastelt:
1
%{
2
#include <stdio.h>
3
#include "y.tab.h"
4
5
#ifndef YYERRCODE
6
#define YYERRCODE 256
7
#endif
8
9
extern int yylval;
10
extern int tmpint;
11
extern char tmpchr;
12
%}
13
%%
14
acloops return TOKACLOO;
15
autocal return TOKAUTOC;
16
adc return TOKADC;
17
calib return TOKCALIB;
18
cycle return TOKCYC;
19
ctrl return TOKCTRL;
20
dispb10 return TOKDBEL10;
21
dismod return TOKDISPMD;
22
dac return TOKDAC;
23
eeprom return TOKEEPROM;
24
offset return TOKOFFSET;
25
order return TOKORDER;
26
solenoid return TOKSOL;
27
staples return TOKSTAPLES;
28
staple return TOKSTAP;
29
smooth return TOKSMOOTH;
30
saving return TOKSAV;
31
slope return TOKSLOPE;
32
set return TOKSET;
33
get return TOKGET;
34
rounding return TOKROUND;
35
rtc return TOKRTC;
36
median return TOKMEDIAN;
37
mwcorr return TOKMWCOR;
38
meas return TOKMEAS;
39
tcoff return TOKTCOFF;
40
tcalib return TOKTCALIB;
41
warmup return TOKWARM;
42
[abc][01] yylval=(int)((yytext[0]-'a')<<1)|yytext[1]-'0'; return N
Das ist ne gekürzte Variante, länger wäre noch langweiliger...
Mein Problem dabei ist nicht das das nicht funktioniert, sondern das
Ganze gegen Unfug abzudichten, Ich möchte bei Syntaxfehlern Meldungen,
und nach Fehlern gerne das die fehlerhafte Zeile verworfen wird und
wieder ein Prompt erscheint. Nach einem einzelnen Newline hätte ich
gerne einen neuen Prompt..
Ich habe jetzt schon seit ein paar Tagen die lustigsten Spielchen durch,
aber ich kriege das nicht hin..was mache ich falsch?
Gruß,
Holm
Du verwendest lex und yacc, das machst du falsch :-)
Die Buffern ihren I/O und sind nicht für
Kommandozeilenverwendung gedacht.
Das lässt sich irgendwie abdrehen, eventuell mit setvbuf,
ich glaube aber, dass die Algorithmen dahinter ziemlich
viele Token vorrausschauen, wird ja oft als Vorteil gesehen.
udok schrieb:> Du verwendest lex und yacc, das machst du falsch :-)
Hmm...
>> Die Buffern ihren I/O und sind nicht für> Kommandozeilenverwendung gedacht.> Das lässt sich irgendwie abdrehen, eventuell mit setvbuf,> ich glaube aber, dass die Algorithmen dahinter ziemlich> viele Token vorrausschauen, wird ja oft als Vorteil gesehen.
Ja, es gibt diese Mechanismen, yacc löffelt 3 Tokens bis er aus dem
Fehlerstatus wieder heraus kommt und man kann ihn resynchronisieren..was
mir allerdings mit '\n' als Synchronisationscharakter nicht recht
gelingen will.
Das Puffern der Eingabe macht mir wenig Sorgen, ich übertrage die
Kommandos
sowieso Zeilenweise und durch '\n' abgeschlossen. Mir reicht es, wenn
nach einer fehlerfreien Zeile ein OK kommt und nach einer
Fehlerbehafteten ein ERROR, aber bitte nicht 3.7 Stück davon. Außerdem
hätte ich gerne nach einer leeren Eingabezeile wieder ein OK (der
Versuch das zu basteln ist mit promptl() im Parser zu sehen, L für
..leer....
Warum soll die Verwendung von lex und yacc falsch sein? Die wurden mal
für solche Zwecke gemacht, ich unterfordere sie eher...
Gruß,
Holm
udok schrieb:> Die Buffern ihren I/O und sind nicht für Kommandozeilenverwendung> gedacht.> Das lässt sich irgendwie abdrehen
Meiner Erinnerung nach hat flex dafür irgendeine Option.
Yep, -I. Die Doku sagt dazu:
1
'flex' scanners default to 'interactive' unless you use the '-Cf'
2
or '-CF' table-compression options (*note Performance::). That's
3
because if you're looking for high-performance you should be using
4
one of these options, so if you didn't, 'flex' assumes you'd rather
5
trade off a bit of run-time performance for intuitive interactive
6
behavior.
Sollte also kein grundlegendes Problem sein. Habe auch schon mal
(spaßeshalber) einen kleinen BASIC-Interpreter für AVRs mit flex und
byacc geschrieben; das funktionierte durchaus, auch interaktiv.
...hab das -I ausprobiert...kein Unterschied. So richtig verwunderlich
isses aber nicht:
" Flex scanners default to interactive unless you use the -Cf or
-CF table-compression options (see below). "
Hmm...
..sehe gerade Jörg hat das auch geschrieben. Es sollte also prinzipiell
funktionieren.
..muß erst mal was Andres machen.
Gruß,
Holm
Ich hab nicht alles gelesen oder verstanden. Daher bitte um Nachsicht,
aber man kann den Buffer von flex zur Laufzeit flushen. Yy_flush_buffer.
Dann muss er neu einlesen.
Ich benutze das weil ich verschiedene Sachen aus einer Datei parsen mir
und dazu Lexer und Parser tausche. Beim Wechsel muss die Datei an der
richtigen Stelle stehen und der ziel-lexer muss geflusht sein damit es
geht.
Holm T. schrieb:> Mein Problem dabei ist nicht das das nicht funktioniert, sondern das> Ganze gegen Unfug abzudichten, Ich möchte bei Syntaxfehlern Meldungen,> und nach Fehlern gerne ...
Das dürfte mit Bison / YACC nicht so einfach sein. Zum Beispiel werden
entsprechende Parser im GCC seit langem nicht mehr durch Generatoren
erzeugt sondern sind handgeklöppelt. Ein Grund dafür ist, dass es fast
unmöglich war, sinnvolle Diagnostics zu bekommen bzw. sinnvolle
Diagnostics und weiteres Verhalten nur in unbefriedigendem Umfang ode
nicht mit vertretbarem Aufwand oder Wartbarkeitsverlust zu realisieren
war.
Zwar verwendest zu eine deutlich einfachere Sprache als die von GCC zu
parsenden, aber dennoch erhälst du besser zu kontrollierendes Verhalten,
insbesondere bei Syntaxproblemen, wohl am einfachstem mit eigenem
Parser.
Die Hacks und Tricks, die in einem Parser-Generator nötig wären, werden
einen Großteil des Comforts, den der Einsatz eines solchen Generators
bieten soll, zunichte gemacht.
..naja..ganz so schlimm isses ja wohl auch wieder nicht und ein Projekt
in der Größe eines GCC habe ich nicht vor.
Jörg (Tm) hat den Parser von avrdude auch mit lex und yacc
gebastelt..scheint doch zu funktionieren :-)
Ich habe Jörg über meinen Krempel mal drüber gucken lassen und das
funktioniert jetzt schon ganz brauchbar. Mal sehen zu welcher Größe das
sich auswächst, im Endeffekt soll das mal auf einen Xmega.
Gruß,
Holm
Johann L. schrieb:> Die Hacks und Tricks, die in einem Parser-Generator> nötig wären, werden einen Großteil des Comforts, den> der Einsatz eines solchen Generators bieten soll,> zunichte gemacht.
Könntest Du dafür ein, zwei Beispiele geben, die auch
für einen Nicht-Compilerbauer verständlich sind?
Jörg W. schrieb:> Für den Xmega solltest du aber meine AVR-Patches für flex und byacc> benutzen, damit er die Tabellen nicht in den RAM sondern in den Flash> wirft.>> https://www.avrfreaks.net/comment/366056#comment-366056
Ok, das sehe ich mir an.. hatte sowieso vor den Output in dieser
Richtung zu überarbeiten. Wenn das schon "aus der Dose" gibt, ist das ne
feine Sache!
Gruß,
Holm