public void ParamListAdd(PhysicalQuantityFunctionParam param)
 {
     if (formalparamlist == null)
     {
         formalparamlist = new List <PhysicalQuantityFunctionParam>();
     }
     formalparamlist.Add(param);
 }
        public static PhysicalQuantityFunctionParam ParseFunctionParam(ref String commandLine, ref String resultLine)
        {
            commandLine = commandLine.ReadIdentifier(out var ParamName);
            Debug.Assert(ParamName != null);

            Unit ParamUnit = PhysicalCalculator.Expression.PhysicalExpression.ParseOptionalConvertToUnit(ref commandLine, ref resultLine);

            PhysicalQuantityFunctionParam param = new PhysicalQuantityFunctionParam(ParamName, ParamUnit);

            return(param);
        }
        public static IFunctionEvaluator ParseFunctionDeclaration(CalculatorEnvironment localContext, ref String commandLine, ref String resultLine)
        {
            // FUNC = FUNCNAME "(" PARAMLIST ")" "{" FUNCBODY "}" .

            // FUNC = FUNCNAME #1 "(" #2 PARAMLIST #3  ")" #4 "{" FUNCBODY "}" .


            Boolean OK = true;

            if (localContext.ParseState == CommandParserState.ReadFunctionParameterList)
            {
                if (commandLine.StartsWith("//"))
                {   // #1
                    commandLine = null;
                    return(null);
                }

                OK = TokenString.ParseToken("(", ref commandLine, ref resultLine);

                localContext.ParseState = CommandParserState.ReadFunctionParameters;
            }
            if (String.IsNullOrEmpty(commandLine))
            {
                return(null);
            }

            if (((localContext.ParseState == CommandParserState.ReadFunctionParameters ||
                  localContext.ParseState == CommandParserState.ReadFunctionParametersOptional) &&
                 !commandLine.StartsWith(")")) ||
                (localContext.ParseState == CommandParserState.ReadFunctionParameter))
            {
                Boolean MoreParamsToParse;
                do
                {
                    if (commandLine.StartsWith("//"))
                    {   // #2
                        commandLine = null;
                        return(null);
                    }

                    if ((localContext.ParseState == CommandParserState.ReadFunctionParameters) ||
                        (localContext.ParseState == CommandParserState.ReadFunctionParameter))
                    {
                        PhysicalQuantityFunctionParam param = ParseFunctionParam(ref commandLine, ref resultLine);

                        OK &= param != null;
                        localContext.FunctionToParseInfo.Function.ParamListAdd(param);
                        localContext.ParseState = CommandParserState.ReadFunctionParametersOptional;

                        if (commandLine.StartsWith("//"))
                        {   // #3
                            commandLine = null;
                            return(null);
                        }
                    }

                    MoreParamsToParse = TokenString.TryParseToken(",", ref commandLine);
                    if (MoreParamsToParse)
                    {
                        localContext.ParseState = CommandParserState.ReadFunctionParameter;
                    }
                } while (OK &&
                         !String.IsNullOrEmpty(commandLine) &&
                         MoreParamsToParse);
            }

            if (OK && !String.IsNullOrEmpty(commandLine))
            {
                if ((localContext.ParseState == CommandParserState.ReadFunctionParameters) ||
                    (localContext.ParseState == CommandParserState.ReadFunctionParametersOptional))
                {
                    OK = TokenString.ParseToken(")", ref commandLine, ref resultLine);

                    if (OK)
                    {
                        localContext.ParseState = CommandParserState.ReadFunctionBlock;
                    }
                }
                if (OK)
                {
                    if (!String.IsNullOrEmpty(commandLine))
                    {
                        if (localContext.ParseState == CommandParserState.ReadFunctionBlock)
                        {
                            if (commandLine.StartsWith("//"))
                            {   // #4
                                commandLine = null;
                                return(null);
                            }

                            OK = TokenString.ParseToken("{", ref commandLine, ref resultLine);
                            if (OK)
                            {
                                localContext.ParseState        = CommandParserState.ReadFunctionBody;
                                localContext.CommandBlockLevel = 1;
                            }
                        }
                        if (localContext.ParseState == CommandParserState.ReadFunctionBody)
                        {
                            if (!String.IsNullOrEmpty(commandLine))
                            {
                                String TempcommandLine   = commandLine;
                                int    indexStartComment = commandLine.IndexOf("//");
                                if (indexStartComment >= 0)
                                {   // Command are terminated by "//"
                                    TempcommandLine = TempcommandLine.Substring(0, indexStartComment);
                                }

                                string NoCommentCommandLine = TempcommandLine;

                                int indexCommandBlockBegin = TempcommandLine.IndexOf('{');
                                int indexCommandBlockEnd   = TempcommandLine.IndexOf('}');

                                while (localContext.CommandBlockLevel > 0 && (indexCommandBlockBegin >= 0 || indexCommandBlockEnd >= 0))
                                {
                                    Boolean beginIsBeforeEnd = (indexCommandBlockBegin >= 0 && (indexCommandBlockEnd <0 || indexCommandBlockEnd> indexCommandBlockBegin));
                                    if (beginIsBeforeEnd)
                                    {
                                        localContext.CommandBlockLevel++;
                                        int skipLen = indexCommandBlockBegin + 1;
                                        TempcommandLine = TempcommandLine.Length > skipLen?TempcommandLine.Substring(skipLen) : "";

                                        indexCommandBlockBegin = TempcommandLine.IndexOf('{');
                                        indexCommandBlockEnd  -= skipLen;
                                    }
                                    else
                                    {
                                        localContext.CommandBlockLevel--;
                                        int skipLen = indexCommandBlockEnd;
                                        if (localContext.CommandBlockLevel > 0)
                                        {   // Include '}' if it is not the end of this function block
                                            skipLen++;
                                        }
                                        TempcommandLine = TempcommandLine.Length > skipLen?TempcommandLine.Substring(skipLen) : "";

                                        indexCommandBlockBegin -= skipLen;
                                        indexCommandBlockEnd    = TempcommandLine.IndexOf('}');
                                    }
                                }
                                ;

                                int indexCommandEnd = -1;
                                if (localContext.CommandBlockLevel > 0)
                                {   // function block are not terminated by '}'
                                    // Whole commandLine is part of Command Block
                                    indexCommandEnd = commandLine.Length;
                                }
                                else
                                {
                                    indexCommandEnd = NoCommentCommandLine.Length - TempcommandLine.Length;
                                }

                                if (indexCommandEnd > 0)
                                {
                                    if (localContext.FunctionToParseInfo.Function.Commands == null)
                                    {
                                        // localContext.FunctionToParseInfo.Function.Commands = new List<String>();
                                    }
                                    Debug.Assert(localContext.FunctionToParseInfo.Function.Commands != null);
                                    localContext.FunctionToParseInfo.Function.Commands.Add(commandLine.Substring(0, indexCommandEnd));
                                    commandLine = commandLine.Substring(indexCommandEnd);
                                }

                                if (localContext.CommandBlockLevel == 0)
                                {
                                    OK = TokenString.ParseToken("}", ref commandLine, ref resultLine);
                                    if (OK)
                                    {   // Completed function declaration parsing
                                        localContext.ParseState = CommandParserState.ExecuteCommandLine;
                                        return(localContext.FunctionToParseInfo.Function);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return(null);
        }