%{ #include "ParsingSymbols.h" #include "Parser.h" #include #include #include #include #include #include #define YY_DECL int yylex (YYSTYPE *lvalp) #define yylval (*lvalp) int yywrap(void) { // no more bufers return 1; }; static int _iBlockDepth = 0; static int _iDummyDepth = 0; static CTString _strCmd = ""; // currently parsed command static int _ctCmdParam = 1; // current parameter index static BOOL _bCmdParamCountErrorReported = FALSE; void TranscriptEsc(CTString &str) { char *pchSrc = (char *)(const char *)str; char *pchDst = (char *)(const char *)str; // if quoted if (pchDst[0] == '"') { int len = strlen(pchDst); pchDst[len-1] = 0; memmove(pchDst, pchDst+1, len-1); } for (;;pchSrc++, pchDst++) { if (*pchSrc==0) { break; } if (*pchSrc!='\\') { *pchDst = *pchSrc; continue; } pchSrc++; switch(*pchSrc) { case 'n': *pchDst = 10; break; case 'r': *pchDst = 13; break; default: *pchDst = *pchSrc; break; } } *pchDst=0; } %} %x COMMENT %x DUMMYBLOCK %x INCLUDE %x COMMAND DIGIT [0-9] HEXDIGIT [0-9A-Fa-f] IDENTIFIERFIRST [A-Za-z_] IDENTIFIEROTHER [A-Za-z0-9_] DOUBLEQUOTE \" STRINGCONTENT ([^\"]|(\\\")) CHARCONTENT ([^\']|(\\\')) NONEXP_FLT ({DIGIT}+"."{DIGIT}*) EXP_FLT (({DIGIT}+("."({DIGIT}*)?)?)("E"|"e")("+"|"-")?{DIGIT}+) PARAMCONTENT ([^\ \n\";]|(\\\ )) %% /*\0 yyterminate();*/ /* Include file parsing. */ "include" BEGIN(INCLUDE); [ \t]*"\"" /* eat the whitespace until first quote */ [^"\""]*"\"" { /* get the include file name until second quote */ if (ShellGetBufferStackDepth() >= SHELL_MAX_INCLUDE_LEVEL) { _pShell->ErrorF("Script files nested too deeply"); } char strFileName[256]; strcpy(strFileName, yytext); strFileName[strlen(strFileName)-1] = 0; CTString strIncludeFile; try { strIncludeFile.Load_t(CTString(strFileName)); ShellPushBuffer(strFileName, strIncludeFile, FALSE); } catch(char *strError) { _pShell->ErrorF("Cannot load script file '%s': %s", yytext, strError); } BEGIN(INITIAL); } . { /* something unrecognized inside include statement */ _pShell->ErrorF("Wrong syntax for include statement"); BEGIN(INITIAL); } /* command parsing */ {PARAMCONTENT}*|"\""{STRINGCONTENT}*"\"" { // for each parameter _ctCmdParam++; CTString strParam = yytext; TranscriptEsc(strParam); // insert the parameter in the command string CTString strParamNo = CTString(1, "%%%d", _ctCmdParam); if (strParam.FindSubstr(strParamNo)!=-1) { _pShell->ErrorF("Parameter substitution recursion detected!"); } else { INDEX ctFound=0; for(;; ctFound++) { if (!_strCmd.ReplaceSubstr(strParamNo, strParam)) { break; } } // if not found and parameter count error not reported yet if (ctFound==0 && !_bCmdParamCountErrorReported) { // report error _bCmdParamCountErrorReported = TRUE; _pShell->ErrorF("Too many parameters for command expansion"); } } } \n|; { // at the end of the command // switch to the new input buffer with that command ShellPushBuffer(ShellGetBufferName(), _strCmd, FALSE); BEGIN(INITIAL); } <> { if (ShellPopBuffer()) { yyterminate(); } } /* special data types */ "FLOAT" { return(k_FLOAT);} "INDEX" { return(k_INDEX);} "CTString" { return(k_CTString);} /* keywords */ "void" { return(k_void); } "const" { return(k_const); } "user" { return(k_user); } "persistent" { return(k_persistent); } "extern" { return(k_extern); } "pre" { return(k_pre); } "post" { return(k_post); } "help" { return(k_help); } "if" { return(k_if); } "else" { return(k_else); } "else"" "*"if" { return(k_else_if); } "<=" { return (LEQ); } ">=" { return (GEQ); } "==" { return (EQ); } "!=" { return (NEQ); } ">>" { return (SHR); } "<<" { return (SHL); } "&&" { return (LOGAND); } "||" { return (LOGOR); } /* single character operators and punctuations */ ";"|"("|")"|"="|"+"|"-"|"<"|">"|"!"|"|"|"&"|"*"|"/"|"%"|"^"|"["|"]"|":"|","|"."|"?"|"~" { return(yytext[0]);} /* constants */ {DIGIT}+ { yylval.val.iIndex = atoi(yytext); return(c_int); } "0x"{HEXDIGIT}+ { yylval.val.iIndex = strtoul(yytext+2, NULL, 16); return(c_int); } {NONEXP_FLT}("f"|"F")? { yylval.val.fFloat = (float) atof(yytext); return(c_float); } {EXP_FLT}("f"|"F")? { yylval.val.fFloat = (float) atof(yytext); return(c_float); } "\""{STRINGCONTENT}*"\"" { CTString &strNew = _shell_astrTempStrings.Push(); // remove double-quotes strNew = yytext; // parse escape symbols and remove double quotes TranscriptEsc(strNew); yylval.val.strString = (const char*)strNew; return(c_string); } "'"{CHARCONTENT}"'" { return(c_char); } /* identifier */ {IDENTIFIERFIRST}{IDENTIFIEROTHER}* { // get the symbol yylval.pssSymbol = _pShell->GetSymbol(yytext, FALSE); BOOL bCommand = FALSE; // if it is string if (_shell_ast[yylval.pssSymbol->ss_istType].st_sttType==STT_STRING) { // get the value CTString str = *(CTString*)yylval.pssSymbol->ss_pvValue; // if the value tells that it is a command if (str.RemovePrefix("!command ")) { // parse the command bCommand = TRUE; _strCmd = str; _ctCmdParam = 0; _bCmdParamCountErrorReported = FALSE; BEGIN(COMMAND); } } // normally, just return the identifier if (!bCommand) { return(identifier); } } ${IDENTIFIERFIRST}{IDENTIFIEROTHER}* { // special case of identifier, used to bypass command parsing // get the symbol yylval.pssSymbol = _pShell->GetSymbol(yytext+1, FALSE); return(identifier); } /* eat up or execute blocks */ "{" { _iBlockDepth++; if (!_bExecNextBlock) { _iDummyDepth++; BEGIN(DUMMYBLOCK); } return block_beg; } "}" { _iBlockDepth--; if (_iBlockDepth<0) { _pShell->ErrorF("Mismatched '}'"); } return block_end; } "{" { _iBlockDepth++; _iDummyDepth++; } "}" { _iBlockDepth--; _iDummyDepth--; if (_iDummyDepth==0) { BEGIN(INITIAL); return block_end; } } . {} /* eat up comments */ "/*" { BEGIN(COMMENT); } "*/" { BEGIN(INITIAL); } . {} "//"[^\n]*\n { ShellCountOneLine(); } /* eat up whitespace */ [ \t]+ { } /* eat up linefeeds and count lines in all conditions */ <*>\n { ShellCountOneLine(); } /* for all unrecognized characters */ . { // report an error _pShell->ErrorF("Unrecognized character '%c' (ASCII 0x%02x)", yytext[0], yytext[0] ); } %%