/* * QT AGI Studio :: Copyright (C) 2000 Helen Zommer * * Almost all of this code was adapted from the Windows AGI Studio * developed by Peter Kelly. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "logic.h" #include "game.h" #include "logedit.h" #include "menu.h" #include #include #include extern TStringList InputLines; //temporary - //input text from the editor window or file static bool UseTypeChecking = true; static int ResPos,LogicSize; static TStringList EditLines,IncludeFilenames; static string DefineNames[MaxDefines]; static string DefineValues[MaxDefines]; static int NumDefines; static int RealLineNum[65535], LineFile[65535]; static int DefineNameLength[MaxDefines]; static string Messages[MaxMessages]; static bool MessageExists[MaxMessages]; typedef struct{ string Name; int Loc; }TLogicLabel; static TLogicLabel Labels[MaxLabels+1]; static int NumLabels; static bool ErrorOccured; static int CurLine; static string LowerCaseLine,ArgText,LowerCaseArgText; static string::size_type LinePos,LineLength,ArgTextLength,ArgTextPos; static bool FinishedReading; static int CommandNameStartPos; static string CommandName; static int CommandNum; static bool NOTOn; char empty_tmp[] = {0}; extern const char EncryptionKey[]; static int EncryptionStart; //************************************************* static void WriteByte(byte b) { if(ResPos < ResourceData.Size){ ResourceData.Data[ResPos++]=b; if(ResPos > LogicSize)LogicSize=ResPos; } } static void WriteByteAtLoc(byte b,int Loc) { if(Loc < ResourceData.Size){ ResourceData.Data[Loc]=b; if(Loc > LogicSize)LogicSize= Loc; } } static void WriteLSMSWord(short word) { WriteByte(word % 256); WriteByte(word / 256); } //************************************************* void Logic::ShowError(int Line, string ErrorMsg) { int LineNum = RealLineNum[Line]; if(LineFile[Line] == 0 || Line > EditLines.num){ // error is in logic in editor window sprintf(tmp,"Line %d: %s\n",RealLineNum[Line],ErrorMsg.c_str()); } else{ //error in include file if (LineFile[Line] > IncludeFilenames.num){ sprintf(tmp,"[unknown include file] Line ???: %s\n",ErrorMsg.c_str()); } else{ sprintf(tmp,"File %s Line %d: %s\n",IncludeFilenames.at(LineFile[Line]-1).c_str(),LineNum,ErrorMsg.c_str()); } } ErrorList.append(tmp); ErrorOccured=true; } //*************************************************** string Logic::ReadString(string::size_type *pos, string& str) //returns string without quotes, starting from pos1 //pos is set to the 1st char after string { string::size_type pos1 = *pos; string::size_type pos2 = pos1; // printf ("ReadString: str=%s pos=%d\n",str.c_str(),*pos); do{ pos2 = str.find_first_of("\"",pos2+1); if(pos2 == string::npos){ ShowError(CurLine,"\" required at end of string."); printf("string: *%s*\n",str.c_str()); return ""; } }while(str[pos2-1]=='\\'); *pos = pos2+1; if(pos2==pos1+1){ return ""; } return str.substr(pos1+1,pos2-pos1-1); } //*************************************************** int Logic::RemoveComments(TStringList Lines) { int CommentDepth = 0; for(CurLine=0;CurLine0 && Line.substr(i,2) == "*/" ){ --CommentDepth; ++i; continue; } } if ( CommentDepth == 0 ){ if(Line[i]=='\"' && (i==0 || Line[i-1] != '\\')) InQuotes = !InQuotes; NewLine += Line[i]; } } Lines.replace(CurLine,NewLine); } return 0; } //*************************************************** int Logic::AddIncludes() { TStringList IncludeStrings,IncludeLines; int CurInputLine,CurIncludeLine; string filename; int err=0; string::size_type pos1,pos2; int CurLine; char *ptr; IncludeFilenames = TStringList(); IncludeStrings = TStringList(); EditLines = TStringList(); IncludeLines = TStringList(); CurLine = 0; for(CurInputLine = 0;CurInputLinedir.c_str(),filename.c_str()); FILE *fptr = fopen(tmp,"rb"); if(fptr==NULL){ sprintf(tmp,"Can't open include file: %s/src/%s",game->dir.c_str(),filename.c_str()); ShowError(CurLine,tmp); err=1; continue; } IncludeLines.lfree(); while(fgets(tmp,MAX_TMP,fptr)!=NULL){ if((ptr=strchr(tmp,0x0a)))*ptr=0; if((ptr=strchr(tmp,0x0d)))*ptr=0; IncludeLines.add(tmp); } fclose(fptr); if(IncludeLines.num==0)continue; IncludeFilenames.add(filename); RemoveComments(IncludeLines); EditLines.replace(CurLine,empty_tmp); for(CurIncludeLine=0;CurIncludeLine= MaxDefines){ ShowError(CurLine,"Too many defines (max " + IntToStr(MaxDefines) + ")"); err=1; continue; } pos1 = str.find_first_not_of(" ",1); pos2 = str.find_first_of(" ",pos1); if(pos1 == string::npos||pos2 == string::npos){ ShowError(CurLine,"Missing define name !"); err=1; continue; } ThisDefineName = str.substr(pos1,pos2-1); if(ThisDefineName.find_first_not_of("qwertyuiopasdfghjklzxcvbnm1234567890._") != string::npos){ ShowError(CurLine,"Define name can contain only characters from [a-z],'.' and '_'."); err=1; continue; } for(i=0;i MaxLabels){ ShowError(CurLine,"Too many labels (max "+IntToStr(MaxLabels)+")"); err=1;continue; } if(LabelName == "if" || LabelName == "else" || LabelName == "goto"){ ShowError(CurLine,"Invalid label name ("+LabelName+")"); err=1;continue; } for(i=0;iNumLines){ FinishedReading = true; return; } do{ LowerCaseLine = EditLines.at(CurLine); if(LowerCaseLine == empty_tmp || (LinePos=LowerCaseLine.find_first_not_of(" ")) == string::npos){ CurLine++; continue; } //printf("Line %d: %s\n",CurLine,LowerCaseLine.c_str()); toLower(&LowerCaseLine); LineLength = LowerCaseLine.length(); return; }while(CurLine0 && (str[i-1]==' ' || str[i-1]=='\t')) --i; return str.substr(0,i); } //*************************************************** string Logic::ReplaceDefine(string InText) { string str=InText; toLower(&str); for(int i=0;i= LineLength || EditLines.at(CurLine)[LinePos] != '('){ ShowError(CurLine,"'(' expected."); return; } LinePos++; if(CmdNum==14 && CommandIsIf){ //said test command NumSaidArgs = -1; FinishedReadingSaidArgs = false; do{ ReadArgText(); NumSaidArgs++; if(ArgText[0]=='"'){ ArgValue=0; ArgTextPos=0; ThisWord=ReadString(&ArgTextPos,ArgText); if(ErrorOccured) ShowError(CurLine,"\" required at end of word."); else{ //find word group number bool found=false; for(int k=0;kNumGroups;k++){ for(int i=0;iWordGroup[k].Words.num;i++){ if( wordlist->WordGroup[k].Words.at(i) == ThisWord){ ArgValue = wordlist->WordGroup[k].GroupNum; found=true; break; } } if(found)break; } if(!found){ ShowError(CurLine,"Unknown word "+ThisWord+"."); return; } } } else ArgValue = ReadArgValue(); SaidArgs[NumSaidArgs] = ArgValue; if (SaidArgs[NumSaidArgs] < 0 || SaidArgs[NumSaidArgs] > 65535){ ShowError(CurLine,"Invalid word number for argument " +IntToStr(NumSaidArgs)+ " (must be 0-65535)."); SaidArgs[NumSaidArgs] = 0; } if ((LinePos < LineLength) & (LowerCaseLine[LinePos] == ',')){ if (NumSaidArgs > MaxSaidArgs){ ShowError(CurLine,"Too many arguments for said command."); FinishedReadingSaidArgs = true; } } else if(LinePos < LineLength && LowerCaseLine[LinePos] == ')'){ FinishedReadingSaidArgs = true; } else ShowError(CurLine,"',' or ')' expected after argument "+IntToStr(NumSaidArgs)+"."); LinePos++; }while(!FinishedReadingSaidArgs||ErrorOccured); WriteByte(NumSaidArgs+1); for (int i=0;i<=NumSaidArgs;i++){ WriteByte(SaidArgs[i] % 256); WriteByte(SaidArgs[i] / 256); } }//if said test command else{ //other command if (CommandIsIf) ThisCommand = TestCommand[CmdNum]; else ThisCommand = AGICommand[CmdNum]; for (CurArg = 0;CurArg=1 && ArgText[0]=='"'){ // argument is message and given as string ArgTextPos=0; ThisMessage = ""; //splitting the message into lines if it doesn't fit the screen do{ if(ThisMessage != "" && ThisMessage[ThisMessage.length()-1]!=' ')ThisMessage += " "; ThisMessage += ReadString(&ArgTextPos,ArgText); if(LinePos+1>=LineLength || LowerCaseLine.find_first_not_of(" ",LinePos+1)==string::npos){ NextLine(); SkipSpaces(); ReadArgText(); } else break; }while(true); ThisMessageNum = MessageNum(ThisMessage); if (ThisMessageNum > 0){ WriteByte(ThisMessageNum); } else{ ThisMessageNum = AddMessage(ThisMessage); if (ThisMessageNum == 0) ShowError(CurLine,"Too many messages (max 255)."); else WriteByte(ThisMessageNum); } }//argument is message and given as string else if (ThisCommand.argTypes[CurArg] == atIObj && ArgTextLength >= 1 && ArgText[0] == '"'){ // argument is inventory object and given as string ArgTextPos=0; ThisInvObjectName= ReadString(&ArgTextPos,ArgText); if(ThisInvObjectName == "")ShowError(CurLine,"Object name must be at least one character."); else{ for(i=0;iItemNames.num;i++){ if(objlist->ItemNames.at(i)==ThisInvObjectName){ WriteByte(i); break; } } if(i>=objlist->ItemNames.num){ ShowError(CurLine,"Unknown inventory object "+ThisInvObjectName); } } }// argument is inventory object and given as string else{ //normal argument ThisArgTypePrefix = (char *)ArgTypePrefix[(int)ThisCommand.argTypes[CurArg]]; if(UseTypeChecking && (strcmp(LowerCaseArgText.substr(0,strlen(ThisArgTypePrefix)).c_str(),ThisArgTypePrefix))){ ShowError(CurLine,"Invalid or unknown argument type for argument "+IntToStr(CurArg)+" (should be a "+ArgTypeName[(int)ThisCommand.argTypes[CurArg]]+")."); } else{ if (UseTypeChecking)ArgTextPos+=strlen(ThisArgTypePrefix); else while (ArgTextPos < ArgTextLength && !(LowerCaseArgText[ArgTextPos] >= 'a' && LowerCaseArgText[ArgTextPos] <= 'z' )) ArgTextPos++; ArgValue=ReadArgValue(); if(ArgValue<0||ArgValue>255) ShowError(CurLine,"Invalid or missing value for argument "+IntToStr(CurArg)+" (must be 0-255)"); else WriteByte(ArgValue); } }//normal argument if (CurArg < ThisCommand.NumArgs-1){ if (ArgTextPos < ArgTextLength) ShowError(CurLine,"',' expected after argument "+IntToStr(CurArg)+"."); else if(LinePos >= LineLength || LowerCaseLine[LinePos] != ',') ShowError(CurLine,"',' expected after argument "+IntToStr(CurArg)+"."); else LinePos++; } else if (ArgTextPos < ArgTextLength){ ShowError(CurLine,"(1) ')' expected after argument "+IntToStr(CurArg)+"."); printf("Line %s argtextpos=%d arglen=%d\n",LowerCaseLine.c_str(),(int)ArgTextPos,(int)ArgTextLength); } } SkipSpaces(); if (LinePos >= LineLength || LowerCaseLine[LinePos] != ')'){ if (ThisCommand.NumArgs > 0){ ShowError(CurLine,"(2) ')' expected after argument "+IntToStr(ThisCommand.NumArgs)+"."); printf("Line %s argtextpos=%d arglen=%d\n",LowerCaseLine.c_str(),(int)ArgTextPos,(int)ArgTextLength); } else ShowError(CurLine,"')' expected."); } else LinePos++; } } //*************************************************** string Logic::ReadText() { int p = LinePos; string::size_type pos = LowerCaseLine.find_first_of("( ,):",LinePos); if(pos == string::npos){ LinePos = LineLength; return LowerCaseLine.substr(p); } else{ LinePos = pos; return LowerCaseLine.substr(p,pos-p); } } //*************************************************** string Logic::ReadPlainText() { int p = LinePos; string::size_type pos = LowerCaseLine.find_first_not_of("qwertyuiopasdfghjklzxcvbnm1234567890._",LinePos); if(pos == string::npos){ LinePos = LineLength; return LowerCaseLine.substr(p); } else{ LinePos = pos; return LowerCaseLine.substr(p,pos-p); } } //*************************************************** string Logic::ReadExprText() { int p = LinePos; string::size_type pos = LowerCaseLine.find_first_not_of("=+-*/>255) ShowError(CurLine,"Invalid number given or error in expression syntax."); else{ SkipSpaces(); expr = ReadExprText(); SkipSpaces(); ArgText = ReplaceDefine(ReadPlainText()); arg2isvar = (ArgText[0]=='v'); if(arg2isvar) arg2=Val(ArgText.substr(1)); else arg2=Val(ArgText); if(arg2<0||arg2>255) ShowError(CurLine,"Invalid number given or error in expression syntax."); else{ CommandNum=0; AddNOT = false; if(expr == "==")CommandNum = 0x01; //equal else if(expr == "<")CommandNum = 0x03; //less else if(expr == ">")CommandNum = 0x05; //greater else if(expr == "!="){ CommandNum = 0x01; AddNOT = true; } //!equal else if(expr == ">="){ CommandNum = 0x03; AddNOT = true; } //!less else if(expr == "<="){ CommandNum = 0x05; AddNOT = true; } //!greater else ShowError(CurLine,"Expression syntax error"); if(CommandNum>0){ if (arg2isvar)CommandNum++; if (AddNOT) WriteByte(0xFD); WriteByte(CommandNum); WriteByte(arg1); WriteByte(arg2); return true; } } } }//if(ArgText[0]=='v') else if(ArgText[0]=='f'){ arg1 = Val(ArgText.substr(1)); if(arg1<0||arg1>255) ShowError(CurLine,"Invalid number given or error in expression syntax.."); else{ WriteByte(0x07); // isset WriteByte(arg1); return true; } }//if(ArgText[0]=='f') else LinePos = OldLinePos; return false; } //*************************************************** bool Logic::AddSpecialSyntax() { int arg1,arg2,arg3; bool arg2isvar=false,arg3isvar=false,arg2isstar=false; string ArgText="",expr,expr2; int OldLinePos; OldLinePos = LinePos; LinePos -= CommandName.length(); if(CommandName[0]=='*'){ LinePos++; ArgText = "*" + ReplaceDefine(ReadPlainText()); } else ArgText = ReplaceDefine(ReadPlainText()); if(ArgText[0]=='v'){ arg1 = Val(ArgText.substr(1)); if(arg1<0 || arg1>255) ShowError(CurLine,"Invalid number given or error in expression syntax."); else{ SkipSpaces(); expr = ReadExprText(); if(expr == "++"){ WriteByte(0x01); // increment WriteByte(arg1); return true; } else if (expr == "--"){ WriteByte(0x02); // decrement WriteByte(arg1); return true; } else{ if(expr[0]=='*'){ expr = expr.substr(1); LinePos++; } SkipSpaces(); arg2isstar = false; ArgText = ReadPlainText(); if(ReadPlainText() == "" && LowerCaseLine[LinePos-ArgText.length()]=='*'){ LinePos++; ArgText = "*" + ReplaceDefine(ReadPlainText()); } else ArgText = ReplaceDefine(ArgText); if(ArgText[0] == 'v' && !arg2isstar)arg2isvar=true; else if (ArgText.substr(0,2) == "*v" && !arg2isstar) arg2isstar = true; if(arg2isvar)arg2 = Val(ArgText.substr(1)); else if(arg2isstar)arg2 = Val(ArgText.substr(2)); else arg2 = Val(ArgText); if(arg2 <0 || arg2 >255) ShowError(CurLine,"Invalid number given or error in expression syntax."); else{ if(expr == "+=" && !arg2isstar){ if(arg2isvar)WriteByte(0x06); //addv else WriteByte(0x05); //addn WriteByte(arg1); WriteByte(arg2); return true; } else if(expr == "-=" && !arg2isstar){ if(arg2isvar)WriteByte(0x08); //subv else WriteByte(0x07); //subn WriteByte(arg1); WriteByte(arg2); return true; } else if(expr == "*=" && !arg2isstar){ if(arg2isvar)WriteByte(0xa6); //mul.v else WriteByte(0xa5); //mul.n WriteByte(arg1); WriteByte(arg2); return true; } else if(expr == "/=" && !arg2isstar){ if(arg2isvar)WriteByte(0xa8); //div.v else WriteByte(0xa7); //div.n WriteByte(arg1); WriteByte(arg2); return true; } else if(expr == "="){ if(LinePos < LineLength && EditLines.at(CurLine)[LinePos] == ';'){ //must be assignn, assignv or rindirect if (arg2isvar) WriteByte(0x04); // assignv else if (arg2isstar) WriteByte(0x0A); // rindirect else WriteByte(0x03); // assignv WriteByte(arg1); WriteByte(arg2); return true; } else if(arg2 != arg1) ShowError(CurLine,"Expression syntax error"); else{ SkipSpaces(); expr2 = ReadExprText(); SkipSpaces(); ArgText = ReplaceDefine(ReadPlainText()); arg3isvar = (ArgText[0]=='v'); if(arg3isvar)arg3=Val(ArgText.substr(1)); else arg3 = Val(ArgText); if(arg3<0 || arg3>255) ShowError(CurLine,"Invalid number given or error in expression syntax."); else{ if (expr2 == "+"){ if (arg3isvar) WriteByte(0x06); //addv else WriteByte(0x05); //addn WriteByte(arg1); WriteByte(arg3); return true; } else if (expr2 == "-"){ if (arg3isvar) WriteByte(0x08); //subv else WriteByte(0x07); //subn WriteByte(arg1); WriteByte(arg3); return true; } else if (expr2 == "*"){ if (arg3isvar) WriteByte(0xa6); //mul.v else WriteByte(0xa5); //mul.n WriteByte(arg1); WriteByte(arg3); return true; } else if (expr2 == "/"){ if (arg3isvar) WriteByte(0xa8); //div.v else WriteByte(0xa7); //div.n WriteByte(arg1); WriteByte(arg3); return true; } else ShowError(CurLine,"Expression syntax error"); } } }//if(expr == "=") else ShowError(CurLine,"Expression syntax error"); } }//if (expr != "--" && expr != "++") }//if(arg1<0 || arg1>255) }//if(ArgText[0]=='v') else if(ArgText.substr(0,2)=="*v"){ LinePos -= (CommandName.length() -1); ArgText = ReplaceDefine(ReadPlainText()); arg1 = Val(ArgText.substr(1)); if(arg1<0 || arg1>255) ShowError(CurLine,"Invalid number given or error in expression syntax."); else{ SkipSpaces(); expr = ReadExprText(); if(expr != "=")ShowError(CurLine,"Expression syntax error"); else{ SkipSpaces(); ArgText = ReplaceDefine(ReadPlainText()); arg2isvar = (ArgText[0]=='v'); if(arg2isvar)arg2 = Val(ArgText.substr(1)); else arg2 = Val(ArgText); if(arg2 < 0 || arg2 > 255) ShowError(CurLine,"Invalid number given or error in expression syntax."); else{ if(arg2isvar)WriteByte(0x09); //lindirectv else WriteByte(0x0b); //lindirectn WriteByte(arg1); WriteByte(arg2); return true; } } } }//if(ArgText.substr(0,2)=="*v") else LinePos = OldLinePos; return false; } //*************************************************** int Logic::LabelNum(string LabelName) { for(int i=1;i<=NumLabels;i++){ if(Labels[i].Name == LabelName)return i; } return 0; } //*************************************************** bool Logic::LabelAtStartOfLine(string LabelName) { string::size_type pos = LinePos - LabelName.length()-1; if(LowerCaseLine.find_first_not_of(" ")=0;CurMessage--){ if(MessageExists[CurMessage])break; } NumMessages = CurMessage; WriteByte(NumMessages); ResPos = MessageSectionStart + 3 + NumMessages*2; EncryptionStart = ResPos; for (CurMessage = 1;CurMessage<=NumMessages;CurMessage++){ if(!MessageExists[CurMessage]){ MessageLoc[CurMessage]=0; continue; } ThisMessageLength = Messages[CurMessage].length(); MessageLoc[CurMessage] = ResPos - MessageSectionStart - 1; for(int i=0;i>8)&0xff,BlockStartDataLoc[BlockDepth]+1); BlockDepth--; SkipSpaces(); if (LinePos >= LineLength && CurLine < EditLines.num-1)NextLine(); if(LowerCaseLine.substr(LinePos,4) == "else"){ LinePos+=4; SkipSpaces(); if(! BlockIsIf[BlockDepth+1]) ShowError(CurLine,"'else' not allowed after command blocks that start with 'else'."); else if(LinePos >= LineLength || LowerCaseLine[LinePos] != '{') ShowError(CurLine,"'{' expected after else."); else{ LinePos++; BlockDepth++; BlockLength[BlockDepth] +=3; WriteByteAtLoc(BlockLength[BlockDepth]&0xff,BlockStartDataLoc[BlockDepth]); WriteByteAtLoc((BlockLength[BlockDepth]>>8)&0xff,BlockStartDataLoc[BlockDepth]+1); BlockIsIf[BlockDepth] = true; WriteByte(0xfe); BlockStartDataLoc[BlockDepth] = ResPos; WriteByte(0x00); // block length filled in later. WriteByte(0x00); } }//if(LowerCaseLine.substr(LinePos,4) == "else" }//if BlockDepth > 0 }//if LowerCaseLine[LinePos] == '}' else{ ReadCommandName(); if(CommandName == "if"){ WriteByte(0xFF); InIf = true; SkipSpaces(); if(LinePos >= LineLength || EditLines.at(CurLine)[LinePos] != '(') ShowError(CurLine,"'(' expected at start of if statement."); LinePos++; InIfBrackets = false; NumCommandsInIfStatement = 0; AwaitingNextTestCommand = true; } else if(CommandName == "else") ShowError(CurLine,"'}' required before 'else'."); else if(CommandName == "goto"){ if(LinePos >= LineLength || LowerCaseLine[LinePos] != '(') ShowError(CurLine,"'(' expected."); else{ LinePos++; ReadCommandName(); CommandName = ReplaceDefine(CommandName); if (LabelNum(CommandName) == 0) ShowError(CurLine,"Unknown label "+CommandName+"."); else if (NumGotos >= MaxGotos) ShowError(CurLine,"Too many labels (max "+IntToStr(MaxLabels)+")."); else{ NumGotos++; Gotos[NumGotos].LabelNum = LabelNum(CommandName); WriteByte(0xFE); Gotos[NumGotos].DataLoc = ResPos; WriteByte(0x00); WriteByte(0x00); if(LinePos >= LineLength || LowerCaseLine[LinePos] != ')') ShowError(CurLine,"')' expected after label name."); LinePos++; if(LinePos >= LineLength || LowerCaseLine[LinePos] != ';') ShowError(CurLine,"';' expected after goto command."); LinePos++; } } } else{ CommandNum = FindCommandNum(false,CommandName); EncounteredLabel = (LabelNum(CommandName) > 0); if (EncounteredLabel && LinePos < LineLength && LowerCaseLine[LinePos] == ':') LinePos++; else EncounteredLabel = false; EncounteredLabel = (EncounteredLabel && LabelAtStartOfLine(CommandName)); if(EncounteredLabel){ Labels[LabelNum(CommandName)].Loc = ResPos; } else{ if (CommandNum == 255){ // not found if (!AddSpecialSyntax()) ShowError(CurLine,"Unknown action command "+EditLines.at(CurLine).substr(CommandNameStartPos,CommandName.length())+"."); } else{ WriteByte(CommandNum); ReadArgs(false,CommandNum); if (CommandNum == 0)LastCommandWasReturn = true; } if (LinePos >= LineLength || EditLines.at(CurLine)[LinePos] != ';') ShowError(CurLine,"';' expected after command."); LinePos++; }//if we found a label }//command }//if LowerCaseLine[LinePos] != '}' }//(!InIf) if(InIf){ LastCommandWasReturn = false; if (AwaitingNextTestCommand){ if (LowerCaseLine[LinePos] == '('){ if (InIfBrackets)ShowError(CurLine,"Brackets too deep in if statement."); InIfBrackets = true; WriteByte(0xFC); NumCommandsInIfBrackets = 0; LinePos++; }// if LowerCaseLine[LinePos] = '(' else if (LowerCaseLine[LinePos] == ')'){ if (NumCommandsInIfStatement == 0) ShowError(CurLine,"If statement must contain at least one command."); else if(InIfBrackets && (NumCommandsInIfBrackets==0)) ShowError(CurLine,"Brackets must contain at least one command."); else ShowError(CurLine,"Expected statement but found closing bracket."); LinePos++; } else{ NOTOn = false; if (LowerCaseLine[LinePos] == '!'){ NOTOn = true; LinePos++; } SkipSpaces(); ReadCommandName(); CommandNum = FindCommandNum(true,CommandName); if (NOTOn) WriteByte(0xFD); if (CommandNum == 255){ // not found if (!AddSpecialIFSyntax())ShowError(CurLine,"Unknown test command "+EditLines.at(CurLine).substr(CommandNameStartPos,CommandName.length())+"."); } else{ WriteByte(CommandNum); ReadArgs(true,CommandNum); } NumCommandsInIfStatement++; if (InIfBrackets) NumCommandsInIfBrackets++; AwaitingNextTestCommand = false; } } // if AwaitingNextTestCommand else if(LinePos < LineLength){ if(LowerCaseLine[LinePos] == ')'){ LinePos++; if(InIfBrackets){ if (NumCommandsInIfBrackets == 0) ShowError(CurLine,"Brackets must contain at least one command."); else InIfBrackets = false; WriteByte(0xFC); } else{ if (NumCommandsInIfStatement == 0) ShowError(CurLine,"If statement must contain at least one command."); else{ SkipSpaces(); if (LinePos > LineLength || EditLines.at(CurLine)[LinePos] != '{') ShowError(CurLine,"'{' expected after if statement."); LinePos++; WriteByte(0xFF); if (BlockDepth > MaxBlockDepth) ShowError(CurLine,"Too many nested blocks (max "+IntToStr(MaxBlockDepth)+")."); else{ BlockDepth++; BlockStartDataLoc[BlockDepth] = ResPos; BlockIsIf[BlockDepth] = true; WriteByte(0x00); // block length filled in later. WriteByte(0x00); } InIf = false; } } } // else if LowerCaseLine[LinePos] == ')' else if (LowerCaseLine[LinePos] == '!'){ ShowError(CurLine,"'!' can only be placed directly in front of a command."); LinePos++; } else if(LowerCaseLine.substr(LinePos,2) == "&&"){ if (InIfBrackets)ShowError(CurLine,"'&&' not allowed within brackets."); AwaitingNextTestCommand = true; LinePos+=2; } else if(LowerCaseLine.substr(LinePos,2) == "||"){ if (!InIfBrackets) ShowError(CurLine,"Commands to be ORred together must be placed within brackets."); AwaitingNextTestCommand = true; LinePos+=2; } else{ if (InIfBrackets) ShowError(CurLine,"Expected '||' or end of if statement."); else ShowError(CurLine,"Expected '&&' or end of if statement."); } }// if (not AwaitingNextTestCommand) and (LinePos < LineLength) }//if InIf SkipSpaces(); if (ErrorOccured)FinishedReading = true; else if (LinePos >= LineLength)NextLine(); }while(!FinishedReading); if (!LastCommandWasReturn)ShowError(CurLine,"return command expected."); if(InIf){ if (AwaitingNextTestCommand){ if (NumCommandsInIfStatement == 0)ShowError(CurLine,"Expected test command."); else ShowError(CurLine,"Expected another test command or end of if statement."); } else{ if(InIfBrackets)ShowError(CurLine,"Expected '||' or end of if statement."); else ShowError(CurLine,"Expected '&&' or end of if statement."); } } else if (BlockDepth > 0){ ShowError(CurLine,"'}' expected."); } for( CurGoto =1;CurGoto<=NumGotos;CurGoto++){ GotoData = Labels[Gotos[CurGoto].LabelNum].Loc - Gotos[CurGoto].DataLoc - 2; WriteByteAtLoc((GotoData&0xff),Gotos[CurGoto].DataLoc); WriteByteAtLoc((GotoData>>8)&0xff,Gotos[CurGoto].DataLoc+1); } return err; } //*************************************************** int Logic::compile() { int ret,i,j; sprintf(tmp,"%s/words.tok",game->dir.c_str()); ret = wordlist->read(tmp); if(ret)return 1; sprintf(tmp,"%s/object",game->dir.c_str()); ret = objlist->read(tmp,false); if(ret)return 1; objlist->ItemNames.toLower(); // words already in lower case in file so we don't need to convert them for(i=0;iItemNames.num;i++){ if(objlist->ItemNames.at(i).find_first_of("\"")==string::npos)continue; //replace " with \" char *ptr=(char *)objlist->ItemNames.at(i).c_str(); for(j=0;*ptr;ptr++){ if(*ptr=='"'){ tmp[j++]='\\'; tmp[j++]='"'; } else tmp[j++]=*ptr; } tmp[j]=0; objlist->ItemNames.replace(i,tmp); } ResourceData.Size = MaxResourceSize; LogicSize = 0; ResPos = 2; ErrorOccured = false; NumDefines = 0; ErrorList=""; if(RemoveComments(InputLines))return 1; if(AddIncludes())return 1; if(ReadDefines())return 1; if(ReadPredefinedMessages())return 1; if(ReadLabels())return 1; if(CompileCommands())return 1; WriteMessageSection(); EditLines.lfree(); if(ErrorOccured)return 1; // printf("\n************* SUCCESS !!! ***********\n"); ResourceData.Size = LogicSize; return 0; }