/// <summary> /// Parse un block évaluable afin de retourner un IGettable. /// </summary> /// <param name="block"></param> /// <returns></returns> static IGettable ParseEvaluableBlock(EvaluableGroupToken block, GlobalContext mainContext) { EvaluableBlockExpression expr = new EvaluableBlockExpression(); expr.Function = ParseFunction(block, mainContext); expr.Name = block.Name; return(expr); }
/// <summary> /// Parse une fonction dans un EvaluableGroupToken. /// Retourne uniquement la fonction. /// </summary> static Function ParseFunction(EvaluableGroupToken token, GlobalContext mainContext) { TokenList nameTokens = token.ArgumentList.Tokens; // Ici on parcours les jetons de exprToken (qui doit être un OperandToken) // afin de trouver les noms des arguments. // Liste contenant les noms des arguments List <string> argsNamesLists = new List <string>(); // Indique si le prochain jeton doit être une virgule bool needComa = false; foreach (Token tok in nameTokens) { if (needComa && tok.Type != TokenType.Separator) { throw new Exception("Expected ',' token in function declaration"); } else { needComa = false; } // Si c'est un nom : if (tok.Type == TokenType.OperandTokens && ((OperandToken)tok).Tokens.First().Type == TokenType.Noun) { argsNamesLists.Add(((InfoToken)((OperandToken)tok).Tokens.First()).Content); needComa = true; } } // Setup de la déclaration de fonction. Function fun = new Function(); fun.ArgumentNames = argsNamesLists; fun.Body = ParseBlock(token.Block.Tokens, mainContext); fun.Modifiers = ParseEvaluableBlockModifier(token.Modifiers); fun.PrimaryModifier = ParsePrimaryEvaluableBlockModifier(token.PrimaryModifier); return(fun); }
/// <summary> /// Parse une liste de jetons et retourne un block d'instruction. /// </summary> public static Block ParseBlock(TokenList tokens, GlobalContext mainContext) { Block mainBlock = new Block(mainContext); mainBlock.Instructions = new List <ExpressionTree.Instructions.Instruction>(); // Détermine si on a commencé à parser un block if. bool parseIfStarted = false; // On commence le parsing TokenList tokenStack = new TokenList(); tokens.Add(new Token(TokenType.EndOfBlock)); foreach (Token token in tokens) { if (parseIfStarted) { if (token.Type == TokenType.BlockGroup) { tokenStack.Add(token); // Si le dernier statement était un else, alors on termine sur ce jeton. if (tokenStack.Last().Type == TokenType.Statement && ((InfoToken)token).Content == "else") { mainBlock.Instructions.Add(ParseIfStatement(tokenStack, mainContext)); tokenStack.Clear(); parseIfStarted = false; } continue; } else if (token.Type == TokenType.OperandTokens) { // Si on a un statement avant ça (if ou elsif en particulier) if (tokenStack.Last().Type == TokenType.Statement) { // On ne prend une opérande qu'après un if ou elsif InfoToken last = (InfoToken)tokenStack.Last(); if (last.Content == "elsif" || last.Content == "if") { tokenStack.Add(token); continue; } } // Si ce n'est pas le cas, c'est que cette opérande vient après le block // if ou elsif, donc on finit. mainBlock.Instructions.Add(ParseIfStatement(tokenStack, mainContext)); tokenStack.Clear(); parseIfStarted = false; } // Si c'est un elsif : on prend le prochain block else if (token.Type == TokenType.Statement) { InfoToken iToken = (InfoToken)token; if (iToken.Content == "elsif") { tokenStack.Add(iToken); continue; } else if (iToken.Content == "else") { tokenStack.Add(iToken); continue; } else { // c'est un statement qui n'a rien avoir avec ça, donc on termine. mainBlock.Instructions.Add(ParseIfStatement(tokenStack, mainContext)); tokenStack.Clear(); parseIfStarted = false; } } else { mainBlock.Instructions.Add(ParseIfStatement(tokenStack, mainContext)); tokenStack.Clear(); parseIfStarted = false; } } // Les possibilités de patterns : // OperandGroup + ";" : c'est une affectation, s'il n'y a pas de signe 'égal' dedans, // bah c'est rien du tout. // Une Opérande + ";" : c'est soit une déclaration de variable (en deux temps donc), // soit un appel de fonction. // Un statement + une opérande + début de block : statement bien entendu. // Stratégie : on stack les jetons jusqu'à rencontrer un début de block ou // un point virgule. On analyse ensuite ce que l'on trouve :D if (token.Type == TokenType.EndOfInstruction) { mainBlock.Instructions.Add(ParseInstruction(tokenStack, mainContext)); tokenStack.Clear(); } else if (token.Type == TokenType.EvaluableBlock && tokenStack.Count == 0) { // Si la pile de jetons est vide, on est en début d'instruction, on a une déclaration // de fonction. // Sinon, on ajoute seulement le jeton à la liste de jetons (dans le else). EvaluableGroupToken blockToken = (EvaluableGroupToken)token; FunctionDeclarationInstruction ins = new FunctionDeclarationInstruction(); ins.Function = ParseFunction(blockToken, mainContext); ins.FunctionName = blockToken.Name; mainBlock.Instructions.Add(ins); tokenStack.Clear(); } else if (token.Type == TokenType.Statement && ((InfoToken)token).Content == "if") { if (tokenStack.Count != 0) { throw new Exception("Syntax error : unexpected token(s) before 'if' statement"); } tokenStack.Add(token); parseIfStarted = true; } else if (token.Type == TokenType.BlockGroup) // fin de block. { tokenStack.Add(token); mainBlock.Instructions.Add(ParseBlockStatement(tokenStack, mainContext)); tokenStack.Clear(); } else { tokenStack.Add(token); } } return(mainBlock); }