static void AddLiteral(const char* zLit, int nChars, struct Parse *pParse) { TemplateToken *pToken; if (!nChars) return; pToken = (TemplateToken*)malloc(sizeof(TemplateToken) + (nChars+1)*sizeof(char)); assert(pToken); memset(pToken, 0, sizeof(TemplateToken)); if ( (nChars==1 && *zLit=='\n') || (nChars==2 && *zLit=='\n' && *zLit=='\r')) pToken->nType = Newline; else { if (nChars>2 && *zLit=='\n' && *zLit=='\r') { AddLiteral(zLit, 2, pParse); // break tokens zLit+=2; nChars-=2; } else if (nChars>1 && *zLit=='\n') { AddLiteral(zLit, 1, pParse); // break tokens zLit++; nChars--; } pToken->nType = Literal; } pToken->nChars = nChars; AddToken(pToken, pParse); pToken++; strncpy((char*)pToken, zLit, nChars); ((char*)pToken)[nChars]='\0'; }
CARDINAL AddAddressLiteral(BOOLEAN status, CARDINAL value) { LiteralPointer tempLP; if (!status) return AddLiteral(status, value); if (literalPointer == NULL) { literalPointer = mymalloc(sizeof(*literalPointer)); currentLiteralPointer = literalPointer; literalPointer->type = AddressLT; literalPointer->u.offset = value; literalPointer->link = NULL; literalPointer->address = literalAddress; literalPointer->adrSet = pass == 2; if (pass == 1) currentBlockPointer->size += 4;/*Allow another slot for it*/ literalAddress += 4; return literalAddress-4; }; /* if */ tempLP = literalPointer;/*Start of the chain*/ do { if ((tempLP->type == AddressLT) && (tempLP->u.offset == value) && (!tempLP->adrSet || (abs((int)(tempLP->address - programCounter - 8)) < 0x1000))) return tempLP->address; /*I.e. return if address known and in range, or symbol in next pool*/ if (tempLP->link == NULL) { tempLP->link = mymalloc(sizeof(*tempLP)); tempLP = tempLP->link; if (currentLiteralPointer == NULL) currentLiteralPointer = tempLP; tempLP->type = AddressLT; tempLP->u.offset = value; tempLP->link = NULL; tempLP->address = literalAddress; tempLP->adrSet = pass == 2; if (pass == 1) currentBlockPointer->size += 4; /*Allow another slot for it*/ literalAddress += 4; return literalAddress-4; }; tempLP = tempLP->link; } while (1); /* loop */ } /* End AddAddressLiteral */
void NextToken (void) /* Get next token from input stream */ { ident token; /* We have to skip white space here before shifting tokens, since the ** tokens and the current line info is invalid at startup and will get ** initialized by reading the first time from the file. Remember if ** we were at end of input and handle that later. */ int GotEOF = (SkipWhite() == 0); /* Current token is the lookahead token */ if (CurTok.LI) { ReleaseLineInfo (CurTok.LI); } CurTok = NextTok; /* When reading the first time from the file, the line info in NextTok, ** which was copied to CurTok is invalid. Since the information from ** the token is used for error messages, we must make it valid. */ if (CurTok.LI == 0) { CurTok.LI = UseLineInfo (GetCurLineInfo ()); } /* Remember the starting position of the next token */ NextTok.LI = UseLineInfo (GetCurLineInfo ()); /* Now handle end of input. */ if (GotEOF) { /* End of file reached */ NextTok.Tok = TOK_CEOF; return; } /* Determine the next token from the lookahead */ if (IsDigit (CurC) || (CurC == '.' && IsDigit (NextC))) { /* A number */ NumericConst (); return; } /* Check for wide character literals */ if (CurC == 'L' && NextC == '\"') { StringConst (); return; } /* Check for keywords and identifiers */ if (IsSym (token)) { /* Check for a keyword */ if ((NextTok.Tok = FindKey (token)) != TOK_IDENT) { /* Reserved word found */ return; } /* No reserved word, check for special symbols */ if (token[0] == '_' && token[1] == '_') { /* Special symbols */ if (strcmp (token+2, "FILE__") == 0) { NextTok.SVal = AddLiteral (GetCurrentFile()); NextTok.Tok = TOK_SCONST; return; } else if (strcmp (token+2, "LINE__") == 0) { NextTok.Tok = TOK_ICONST; NextTok.IVal = GetCurrentLine(); NextTok.Type = type_int; return; } else if (strcmp (token+2, "func__") == 0) { /* __func__ is only defined in functions */ if (CurrentFunc) { NextTok.SVal = AddLiteral (F_GetFuncName (CurrentFunc)); NextTok.Tok = TOK_SCONST; return; } } } /* No reserved word but identifier */ strcpy (NextTok.Ident, token); NextTok.Tok = TOK_IDENT; return; } /* Monstrous switch statement ahead... */ switch (CurC) { case '!': NextChar (); if (CurC == '=') { SetTok (TOK_NE); } else { NextTok.Tok = TOK_BOOL_NOT; } break; case '\"': StringConst (); break; case '%': NextChar (); if (CurC == '=') { SetTok (TOK_MOD_ASSIGN); } else { NextTok.Tok = TOK_MOD; } break; case '&': NextChar (); switch (CurC) { case '&': SetTok (TOK_BOOL_AND); break; case '=': SetTok (TOK_AND_ASSIGN); break; default: NextTok.Tok = TOK_AND; } break; case '\'': CharConst (); break; case '(': SetTok (TOK_LPAREN); break; case ')': SetTok (TOK_RPAREN); break; case '*': NextChar (); if (CurC == '=') { SetTok (TOK_MUL_ASSIGN); } else { NextTok.Tok = TOK_STAR; } break; case '+': NextChar (); switch (CurC) { case '+': SetTok (TOK_INC); break; case '=': SetTok (TOK_PLUS_ASSIGN); break; default: NextTok.Tok = TOK_PLUS; } break; case ',': SetTok (TOK_COMMA); break; case '-': NextChar (); switch (CurC) { case '-': SetTok (TOK_DEC); break; case '=': SetTok (TOK_MINUS_ASSIGN); break; case '>': SetTok (TOK_PTR_REF); break; default: NextTok.Tok = TOK_MINUS; } break; case '.': NextChar (); if (CurC == '.') { NextChar (); if (CurC == '.') { SetTok (TOK_ELLIPSIS); } else { UnknownChar (CurC); } } else { NextTok.Tok = TOK_DOT; } break; case '/': NextChar (); if (CurC == '=') { SetTok (TOK_DIV_ASSIGN); } else { NextTok.Tok = TOK_DIV; } break; case ':': SetTok (TOK_COLON); break; case ';': SetTok (TOK_SEMI); break; case '<': NextChar (); switch (CurC) { case '=': SetTok (TOK_LE); break; case '<': NextChar (); if (CurC == '=') { SetTok (TOK_SHL_ASSIGN); } else { NextTok.Tok = TOK_SHL; } break; default: NextTok.Tok = TOK_LT; } break; case '=': NextChar (); if (CurC == '=') { SetTok (TOK_EQ); } else { NextTok.Tok = TOK_ASSIGN; } break; case '>': NextChar (); switch (CurC) { case '=': SetTok (TOK_GE); break; case '>': NextChar (); if (CurC == '=') { SetTok (TOK_SHR_ASSIGN); } else { NextTok.Tok = TOK_SHR; } break; default: NextTok.Tok = TOK_GT; } break; case '?': SetTok (TOK_QUEST); break; case '[': SetTok (TOK_LBRACK); break; case ']': SetTok (TOK_RBRACK); break; case '^': NextChar (); if (CurC == '=') { SetTok (TOK_XOR_ASSIGN); } else { NextTok.Tok = TOK_XOR; } break; case '{': SetTok (TOK_LCURLY); break; case '|': NextChar (); switch (CurC) { case '|': SetTok (TOK_BOOL_OR); break; case '=': SetTok (TOK_OR_ASSIGN); break; default: NextTok.Tok = TOK_OR; } break; case '}': SetTok (TOK_RCURLY); break; case '~': SetTok (TOK_COMP); break; default: UnknownChar (CurC); } }
int meta_load_template(const char* zFilename, TemplateToken **ppTemplate) { char cQuote = '%'; char cLP = '['; char cRP = ']'; FILE* pFile = fopen(zFilename, "r"); char buffer[1024]; char command[32]; char arg[32]; char *zEnd, *zCmd = NULL, *zArg = NULL; char c; size_t nChars; struct Parse sParse; struct Caret *pCaret = &sParse.sCaret; struct Caret *pLastCaret = &sParse.sLastCaret; if (!pFile) { fprintf(stderr, "Error opening %s", zFilename); exit(errno); } memset(&sParse, 0, sizeof(sParse)); sParse.zFilename = zFilename; while (fgets(buffer, sizeof(buffer), pFile)) { sParse.sCaret.nLine++; sParse.sCaret.nPos = 1; if (strncmp(buffer, "metaquote", 9)==0) { for (pCaret->z = &buffer[9]; c=*(pCaret->z)==' '||c=='\t'; pCaret->z++); cQuote = *(pCaret->z)++; cLP = *(pCaret->z)++; cRP = *(pCaret->z)++; fprintf(stderr, "Using metachars %c%c%c\n", cQuote, cLP, cRP); } else if (strncmp(buffer, "begin", 5)==0) { sParse.sCaret.nLine++; sParse.sCaret.nPos = 1; sParse.sLastCaret = sParse.sCaret; //fprintf(stderr, "Parsing template...\n"); while (nChars = fread(buffer, sizeof(char), sizeof(buffer), pFile)) { //printf("Parsing chunk: %d\n", nChars); zEnd = buffer+nChars; sParse.sLastCaret.z = buffer; sParse.sCaret.z = buffer; for(pCaret->z = buffer; pCaret->z < zEnd; pCaret->z++) { if ( *(pCaret->z)=='\n' ) { pCaret->nLine++; pCaret->nPos = 1; } else if ( *(pCaret->z)!='\r' ) pCaret->nPos++; switch (sParse.nState) { case stLiteral: if ( *(pCaret->z)==cQuote ) { AddLiteral(pLastCaret->z, pCaret->z-pLastCaret->z, &sParse); SwitchState(stWaitLP, &sParse); } break; case stWaitLP: if ( *(pCaret->z)!=cLP ) { PrintCaret(stderr, &sParse); fprintf(stderr, "'%c' wanted\n", cQuote); return ++sParse.nErrors; } SwitchState(stCommand, &sParse); zCmd = command; break; case stCommand: //for (; (p<pEnd-1) && (p[1]=='\t' || p[1]==' '); p++); if (zCmd >= command+sizeof(command)) { PrintLastCaret(stderr, &sParse); fprintf(stderr, "[Fatal] command too big\n"); return ++sParse.nErrors; } if (c=*(pCaret->z)==cRP || c=='*') { *zCmd = '\0'; AddCommand(command, &sParse); //printf("Command %d:%d: %s\n", sParse.sLastCaret.nLine, sParse.sLastCaret.nPos, command); SwitchState(c=='*' ? stComment : stLiteral, &sParse); } else if( c=*(pCaret->z)==' '||c=='\t' ) { *zCmd = '\0'; //printf("Command with args %d:%d: %s\n", sParse.sLastCaret.nLine, sParse.sLastCaret.nPos, command); for (; c=*(pCaret->z) && (c=='\t' || c==' '); pCaret->z++); SwitchState(stCommandArgs, &sParse); zArg = arg; } else { *zCmd = *(pCaret->z); zCmd++; } break; case stCommandArgs: if (zArg >= arg+sizeof(arg)) { PrintLastCaret(stderr, &sParse); fprintf(stderr, "[Fatal] Command argument too big\n"); return ++sParse.nErrors; } if (*(pCaret->z)==cRP) { *zArg = '\0'; AddCommandArg(command, arg, &sParse); SwitchState(stLiteral, &sParse); } else { *zArg = *(pCaret->z); zArg++; } break; case stComment: if (*(pCaret->z)=='*') { SwitchState(stCommand, &sParse); zCmd = command; } break; } } switch(sParse.nState) { case stLiteral: AddLiteral(pLastCaret->z, zEnd-pLastCaret->z, &sParse); break; } } break; } } fclose(pFile); if (sParse.pItemLoopToken) { PrintCaret(stderr, &sParse); fprintf(stderr, "Unclosed item loop\n"); sParse.nErrors++; } if (sParse.pDialogLoopToken) { PrintCaret(stderr, &sParse); fprintf(stderr, "Unclosed dialog loop\n"); sParse.nErrors++; } fprintf(stderr, "%d tokens created.\n", sParse.pLastToken->nIndex+1); assert(ppTemplate); *ppTemplate = sParse.pFirstToken; return sParse.nErrors; }