   Parsing a simple script
  I am trying to create a simple parser for this script to move certain units in my program around, I am really doing this for a learning purpose before I try and move onto the real deal, but I need to understand a few things and get them figured before I do that. Here is the example scriptmove(left, speedUp, 2) //left is boolean value, speedUp boolean, intI am having a hard time handling "(" and ")" and for some reason my loop isn't working for the reading end of file can someone please assist me here.Here is my source so far, for testing purposes before I implement something in the actual program. Problem one it isn't reading through the whole file I can only get "MOVED" to show.ifstream script;script.open("script.txt");string line, symbol, newSymbol;while(!script.eof()){getline(script, line);for(int i = 0; i < (int)line.size(); i++){symbol += line;while(symbol == "move"){cout << "MOVED" <<endl;symbol = "";}while(symbol == "run"){cout << "RUN" <<endl;symbol = "";}while(symbol == "turnon"){cout << "TURNED ON" <<endl;symbol = "";}while(symbol == "turnoff"){cout << "TURNED OFF" <<endl;symbol = "";}}}
  What does the script that you're testing on look like? You're not checking for parentheses, so you're not going to get any arguments from functions in your scripts.I'd suggest performing string operations on the entire line, as opposed to rebuilding it piece by piece. For example, you can use line.find_first_of('(') to find the end of a function name and the beginning of an argument list, and line.find_last_of(')') to find the end of an argument list.   ;  My example of this script was the "move(left, speedUp, 2)", I have never really got into parsing for functions, so this is quite the challenge for me. I changed my code around a little bit I remembered something from an early class I had that had a little parsing in it, but stuck again...char character;string line;do{getline(script, line);for(int i = 0; i < line.length(); i++){character = line;if(character != '('){token += character;if(token == "move"){cout << "MOVED" << endl;}}}}while(!script.eof());I am just having a hard time figuring out what should go where with out be being a bunch of redundant code... I like your recommendation, but not sure exactly how I would use it properly.   ;  Given your example file, what else should happen? You're only checking for tokens like "move." You don't check for anything else. The program is going to encounter the "move" token, set symbol to "", and then run through the rest of the string and do nothing. You have to write code to parse the function parameters if you want them to be parsed.   ;  Yes, yes I know this, I am asking how I should go about it, that is where I am having trouble parsing the rest of it, handling the ( and skipping it then reading the argument.   ;  After you read your '(', you know the function name and thus the function declaration. In your move you do something like this:stringstream line; // Already in your main function, just here for clarity for the stringstreamstring arg1, arg2, arg3;line.getline(arg1, ',');  // Check for errors!!line.getline(arg2, ',');  // Check for errors!!line.getline(arg3, ')');  // Check for errors!!// Note the ')' in the last function call.// Convert the arg1, arg2 and arg3 to the corresponding variable types and call move(bool, bool, int) in C++Emiel1   ;Quote:Original post by wicked357Yes, yes I know this, I am asking how I should go about it, that is where I am having trouble parsing the rest of it, handling the ( and skipping it then reading the argument.Something like:// Read in the linestring line;getline (script, line);// Find the position of the first open parenthesesint openArgs = line.find_first_of('(');// Take the substring from position 0 to just before// the opening parentheses, i.e. the function namestring funcName = line.substr(0, openArgs - 1);// The rest of the string is the argument list // (plus the closing parentheses)string argList = line.substr(openArgs + 1);// Do the same for each argument, using ',' as your delimiter.// Also remember to check for errors;  There is an easier and better way to do this.Go through the characters in the stream and split them into tokens based on their type. For instance, alphabetic characters introduce an identifier, so m is added to the current token and the current type is considered to be "identifier". ove are all identifier characters, but ( is not, so the identifier move is added to the list of tokens and the default state is resumed.Next, ( is read; since it can function as a token on its own, it too is added, but this time as an "operator" token. Then left is an identifier, , is an operator like (, and so on. 2 is, obviously, a number. Whitespace should automatically separate tokens, except inside strings. When you get to the comment delimiter //, you can just keep reading characters until you get to the end of the line ('\n'), and do nothing with them.When that's done, you now have a list of handy discrete elements to work with. Rather than munging text, you can get to what's really important: parsing your language. A function call, for instance, looks like an identifier followed by an opening parenthesis. You can then quite easily write a set of rules for turning the list of tokens into whatever form you like, and evaluating it to produce effects.I hope you find this helpful!;  I've got some thoughts to share with you --- hopefully not too wordy =)definately separate the logic for your parser and builder ...make them separate classes or whatever.   The Parser should prepare a complete list of "chunks" of text, while the Builder should consume those chunks, one at a time.don't go with a line-by-line parser.   If you do, you may end up having trouble implementing certain features, such as multi-line statements, multi-line comments, etc...Use text chunks.   A chunk of text might be "Move", or maybe a left paren "(".   Create a struct to hold the text, along with various fields to further explain the text, such as LowercaseText, Length, and OriginalLineNo.So first, have the parser break all the code down into those chunks.  At this stage, dont worry about whether a chunk of text is a function, but make a decision as to what type of text it is.  Common types are ALPHA, NUMERIC, SYMBOL, WHITESPACE, and EOL (end of line).   You are basically creating a little database of chunks to be used by the builder.   Take the time to prepare the extra information about each chunk, such as length, lowercase, and original line number.then create functions "GetFirstChunk" and "GetNextChunk" for your parser, which will return one chunk struct at a time.Now, for the builder.  The builder acquires 1 chunk at a time from the parser and acts upon it...One way to do that is to have a main loop which checks for certain keywords, such as your "move" function.   If "move" is the current chunk, call a subroutine titled maybe "BuildFunction".   BuildFunction, as someone suggested previously, could look up the number of parameters for the function, and call GetNextChunk enough times to match the need.  Once the move function is built, return to the main loop, grab the next chunk, lookup the keyword and act upon it.example:Parser.ParseAllchunk = Parser.GetFirstChunkloop while (chunk <> nil)  keyword = lookupKeyword(chunk.Text)  case keyword.Type of    KEYWORD_FUNCTION:  BuildFunction(chunk)    KEYWORD_WHATEVER:  BuildWhatever(chunk)    else Raise "Undefined Keyword: " +chunk.Text  end  chunk = Parser.GetNextChunkendIf the keyword lookup function fails, then you have an error, maybe: "undefined keyword: Moove"    =);  just an fyi, if anyone is interested in this kind of stuff =)If you take the time to build up a fancy Builder.GetNextChunk method, instead of directly acquiring the raw chunks from the Parser, you can implement cool things like compiler directives.{DEF Debug}...{IFDEF Debug} print('debug: MoveTo'); {END} MoveTo(25,25);The fancy GetNextChunk method would strip/process all the compiler directives, feeding the Builder only chunks within define scope.  The Build method would have no idea it was happening, and I'm pretty sure it wouldn't even care....    =)   