%{ #include "olmenu_yacc.h" #include #include #ifndef YYLTYPE struct { int first_line; } yyltype; #define YYLTYPE yyltype #endif #ifdef TEST_LEX YYSTYPE yylval; YYLTYPE yylloc; #else extern YYLTYPE yylloc; #define YY_USER_INIT yylloc.first_line=1; #endif static char rcsid[] = "$Id: olmenu.l,v 1.1.1.1 1999/09/26 12:34:39 mib Exp $"; %} %x CMD %s ACT %x ENV ENV1 ENV2 ID ([A-Za-z_$/\.0-9-]+) QSTR (\"[^\n"]*\") %% BACK_SELN return(BACK_SELN); COLUMNS return(COLUMNS); DEFAULT return(DEFAULT); DIRMENU return(DIRMENU); END return(END); EXIT return(EXIT); EXIT_NO_CONFIRM return(EXIT_NO_CONFIRM); FLIPDRAG return(FLIPDRAG); FLIPFOCUS return(FLIPFOCUS); FULL_RESTORE_SIZE_SELN return(FULL_RESTORE_SIZE_SELN); INCLUDE return(INCLUDE); MENU return(MENU); MOVE_DESKTOP return(MOVE_DESKTOP); NOP return(NOP); OPEN_CLOSE_SELN return(OPEN_CLOSE_SELN); QUIT_SELN return(QUIT_SELN); PIN return(PIN); PROPERTIES return(PROPERTIES); REFRESH return(REFRESH); REREAD_MENU_FILE return(REREAD_MENU_FILE); RESTART return(RESTART); SAVE_WORKSPACE return(SAVE_WORKSPACE); SEPARATOR return(SEPARATOR); START_DSDM return(START_DSDM); STICK_UNSTICK_SELN return(STICK_UNSTICK_SELN); STOP_DSDM return(STOP_DSDM); TITLE return(TITLE); WINMENU return(WINMENU); WMEXIT return(WMEXIT); [0-9]+ { yylval.num = atoi(yytext); return(INT); } ({ID}|{QSTR})+ { BEGIN CMD; yymore(); } ({ID}|{QSTR})+ { BEGIN ACT; yylval.str = strdup(yytext); return(LABEL); /* Label, with quotes */ } \\\n { yylloc.first_line++; yymore(); } \n { yylval.str = strdup(yytext); yylval.str[yyleng-1] = '\0'; yyless(yyleng-1); BEGIN 0; return(EXEC); } .$ { yylval.str = strdup(yytext); BEGIN 0; return(EXEC); } . yymore(); "<" return(*yytext); ">" { BEGIN ACT; return(*yytext); } #.* ; " " | \t ; \n { yylloc.first_line++; BEGIN 0; return(*yytext); } . { BEGIN CMD; yymore(); } [^$]+ return((int)yytext); "$"/[A-Za-z0-9_] BEGIN ENV1; "${" BEGIN ENV2; [A-Za-z0-9_]+ { char *s; s = getenv(yytext); BEGIN ENV; if (s!=NULL) return((int)s); } [^}]+ { char *s; s = getenv(yytext); if (s!=NULL) return((int)s); } "}" BEGIN ENV; .|\n { BEGIN ENV; yymore(); } %% /* This lexer is nice and simple, but it does have a few limitations: (a) You cannot use any keywords as labels, eg: EXIT EXIT would fail, though "EXIT" EXIT is valid (b) A command consisting only of digits will cause a syntax error. Again, quoting will help. The 1st rule that will be matched should be one which returns LABEL. This activates the state ACT. Next, we expect an "action": one or more keywords, or an arbitrary command string, or both. We scan for keywords, but if we find something else, we assume it is a command, and go into the CMD state. Since CMD is exclusive, we build up the rest of the string, one char at a time. The lexer is designed to be fairly flexible, and will treat, say: My" "Menu as a valid, single label (without processing the quotes). One of the more subtle points of the lex-specification is the handling of INT. It relies on Lex's "first, best match" rule. It appears BEFORE the definitions of {ID}, so it RELIES on the fact that these definitions do NOT include spaces or "#", or anything that would make them read more than a single integer. (The same thing applies for the keywords). It is part of the reason for reading the rest of EXEC string using yymore() The other reason for using yymore() is that it lets us pass the command-string as a single token (EXEC), and so we don't have to reassemble the command-string within the parser from several smaller tokens. */ char * expand_env(char *src) { YY_BUFFER_STATE yybuff_env; YY_BUFFER_STATE yybuff_old; char *segment, *result, *bigger; int size, seglen, reslen; size = strlen(src) + 80; result=(char *)malloc(size); *result='\0'; reslen = 0; BEGIN ENV; yybuff_old = YY_CURRENT_BUFFER; yybuff_env = yy_scan_string(src); yy_switch_to_buffer(yybuff_env); while(( segment = (char*)yylex() )) { seglen = strlen(segment); if( size <= reslen + seglen ) { size = reslen + seglen + 1; bigger = (char *)malloc(size); strcpy(bigger,result); free(result); result=bigger; } strcpy(result+reslen,segment); reslen += seglen; } yy_switch_to_buffer(yybuff_old); yy_delete_buffer(yybuff_env); BEGIN 0; return(result); }