%{ /* * The contents of this file are subject to the Mozilla Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * The Initial Developer of this code is David Baum. * Portions created by David Baum are Copyright (C) 1998 David Baum. * All Rights Reserved. * * Portions created by John Hansen are Copyright (C) 2005 John Hansen. * All Rights Reserved. * */ #include #include #include "Symbol.h" #include "RCX_Constants.h" #include "JumpStmt.h" #include "Buffer.h" #include "parser.h" #include "Compiler.h" #include "Error.h" #include "Bytecode.h" #define kMaxFileDepth 16 #define kMaxFileCount 255 typedef struct InputFile { struct InputFile *fNext; int fSourceIndex; YY_BUFFER_STATE fBufferState; long fSavedOffset; const char* fDataPtr; int fDataRemain; } InputFile; static int sFileDepth = 0; static InputFile *sCurrentInputFile = 0; static int sSourceIndex = 0; static long sOffset = 0; static int sReturnWhitespace = 0; static int sInsideDirective = 0; static int sInsideProse = 0; static int FillBuffer(char *ptr, int max); #define YY_DECL int yylex(YYSTYPE &yylval) #define YY_USER_ACTION { sOffset += yyleng; } #define YY_INPUT(buf,res,max) (res = FillBuffer(buf, max)) #define Return(tok, val) do { yylval.fInt = val; return tok; } while(0) // this is a hack so that isatty() and fileno() aren't required for the Win32/macintosh builds #if defined(WIN32) || defined(macintosh) #define YY_NEVER_INTERACTIVE 1 #endif %} %option outfile="lexer.cpp" id0 [a-zA-Z_] idn [a-zA-Z_0-9] digit [0-9] hex [0-9a-fA-F] any [^\r\n] ws [ \t] nl [\r\n] %x COMMENT PREPROC %% "//"{any}* ; \032 ; // hack for DOS EOF characters {nl} { if (sInsideDirective) { sInsideDirective = 0; return NL; } } \\{nl} { } {ws}*"##" { return PP_GLOM; } {ws}*#{ws}* { if (sInsideDirective) return '#'; else { BEGIN(PREPROC); sInsideDirective = 1; } } "include" { BEGIN(INITIAL); return PP_INCLUDE; } "define" { BEGIN(INITIAL); return PP_DEFINE; } "ifdef" { BEGIN(INITIAL); Return(PP_IFDEF, true); } "ifndef" { BEGIN(INITIAL); Return(PP_IFDEF, false); } "if" { BEGIN(INITIAL); return PP_IF; } "else" { BEGIN(INITIAL); return PP_ELSE; } "elif" { BEGIN(INITIAL); return PP_ELIF; } "endif" { BEGIN(INITIAL); return PP_ENDIF; } "undef" { BEGIN(INITIAL); return PP_UNDEF; } "pragma" { BEGIN(INITIAL); return PP_PRAGMA; } "error" { BEGIN(INITIAL); return PP_ERROR; } "warning" { BEGIN(INITIAL); return PP_WARNING; } {nl} { BEGIN(INITIAL); yyless(yyleng-1); return PP_UNKNOWN; } . { BEGIN(INITIAL); return PP_UNKNOWN; } "if" { return IF; } "else" { return ELSE; } "while" { return WHILE; } "do" { return DO; } "for" { return FOR; } "repeat" { return REPEAT; } "break" { yylval.fInt = Bytecode::kBreakFlow; return JUMP; } "continue" { yylval.fInt = Bytecode::kContinueFlow; return JUMP; } "return" { yylval.fInt = Bytecode::kReturnFlow; return JUMP; } "switch" { return SWITCH; } "case" { return CASE; } "default" { return DEFAULT; } "monitor" { return MONITOR; } "acquire" { return ACQUIRE; } "catch" { return CATCH; } "goto" { return GOTO; } "int" { return INT; } "void" { return T_VOID; } "const" { return T_CONST; } "__sensor" { return SENSOR; } "__type" { return TYPE; } "__event_src" { return EVENT_SRC; } "__taskid" { return TASKID; } "__nolist" { return NOLIST; } "__res" { return RES; } "asm" { return ASM; } "task" { return TASK; } "sub" { return SUB; } "stop" { Return( TASKOP, kRCX_StopTaskOp); } "start" { Return( TASKOP, kRCX_StartTaskOp); } "abs" { return ABS; } "sign" { return SIGN; } "+=" { Return( ASSIGN, kRCX_AddVar); } "-=" { Return( ASSIGN, kRCX_SubVar); } "*=" { Return( ASSIGN, kRCX_MulVar); } "/=" { Return( ASSIGN, kRCX_DivVar); } "&=" { Return( ASSIGN, kRCX_AndVar); } "|=" { Return( ASSIGN, kRCX_OrVar); } "||=" { Return( ASSIGN, kRCX_AbsVar); } "+-=" { Return( ASSIGN, kRCX_SgnVar); } ">>=" { Return( ASSIGN2, RIGHT); } "<<=" { Return( ASSIGN2, LEFT); } "%=" { Return( ASSIGN2, '%'); } "^=" { Return( ASSIGN2, '^'); } "==" { return REL_EQ; } "!=" { return REL_NE; } "<=" { return REL_LE; } ">=" { return REL_GE; } "&&" { return AND; } "||" { return OR; } "++" { Return( INCDEC, 1); } "--" { Return( INCDEC, 0); } "true" { return CTRUE; } "false" { return CFALSE; } "<<" { return LEFT; } ">>" { return RIGHT; } "@@" { return INDIRECT; } {id0}{idn}* { yylval.fSymbol = Symbol::Get(yytext); return ID; } 0[xX]{hex}+ { char*ptr; yylval.fInt = strtol(yytext, &ptr, 0); return NUMBER; } {digit}+ { yylval.fInt = (int)atof(yytext); return NUMBER; } "\""[^\"]*"\"" { yytext[yyleng-1]=0; yylval.fString = yytext+1; return STRING; } {ws}+ { if (sReturnWhitespace) return WS; } . { return yytext[0]; } "/*" BEGIN(COMMENT); [^*\r\n]* /* eat anything that's not a '*' */ "*"+[^*/\r\n]* /* eat up '*'s not followed by '/'s */ {nl} /* eat up newlines */ "*"+"/" BEGIN(INITIAL); %% void LexCurrentLocation(LexLocation &loc) { loc.fLength = yyleng; loc.fIndex = sSourceIndex; loc.fOffset = sOffset - yyleng; } void LexReturnWhitespace(int mode) { sReturnWhitespace = mode; } int LexFindAndPushFile(const char *name) { Buffer *b = Compiler::Get()->CreateBuffer(name); if (!b) { Error(kErr_FileOpen, name).RaiseLex(); return 0; } return LexPush(b); } int LexPush(Buffer *b) { InputFile *inputFile; int index; index = Compiler::Get()->AddBuffer(b); // make sure max file depth and file count haven't been exceeded if (sFileDepth == kMaxFileDepth || index > kMaxFileCount) return 0; // save line number and buffer in previous file if (sCurrentInputFile) { sCurrentInputFile->fSavedOffset = sOffset; sCurrentInputFile->fBufferState = YY_CURRENT_BUFFER; } inputFile = (InputFile *)malloc(sizeof(InputFile)); inputFile->fBufferState = yy_create_buffer(0, YY_BUF_SIZE); inputFile->fDataPtr = b->GetData(); inputFile->fDataRemain = b->GetLength(); inputFile->fSourceIndex = index; // link into list inputFile->fNext = sCurrentInputFile; sCurrentInputFile = inputFile; sFileDepth++; // switch to new buffer sOffset = 0; sSourceIndex = index; yy_switch_to_buffer(inputFile->fBufferState); return 1; } int yywrap() { InputFile *inputFile; // check for unterminated comments if (YY_START == COMMENT) { Error(kErr_UnterminatedComment).RaiseLex(); BEGIN(INITIAL); } // if no input files, just return if (sCurrentInputFile == 0) return 1; // pop an input file off the list inputFile = sCurrentInputFile; sCurrentInputFile = inputFile->fNext; sFileDepth--; // cleanup the input file yy_delete_buffer(YY_CURRENT_BUFFER); free(inputFile); // if no more files, just return 1 if (!sCurrentInputFile) return 1; // switch to next file yy_switch_to_buffer(sCurrentInputFile->fBufferState); sOffset = sCurrentInputFile->fSavedOffset; sSourceIndex = sCurrentInputFile->fSourceIndex; // tell yylex() to continue return 0; } void LexReset() { while(yywrap() == 0) ; } int FillBuffer(char *buf, int max_size) { int result; // if no files are pending, return 0 (EOF) if (!sCurrentInputFile) return 0; int n = sCurrentInputFile->fDataRemain; if (n > max_size) n = max_size; memcpy(buf, sCurrentInputFile->fDataPtr, n); sCurrentInputFile->fDataPtr += n; sCurrentInputFile->fDataRemain -= n; result = n; return result; }