public override void TranslateInput()
        {
            // Parse the expression first to determine the result type
            MethodGenerator.SetOutputEnabled(false);
            IrisType resultType = ParseExpressionAndReadFormatSpecifiers();

            MethodGenerator.SetOutputEnabled(true);

            if (_context.ErrorCount == 0)
            {
                // No errors: Now that we know the result type, parse again and generate code this time

                _context.Emitter.BeginProgram(_context.ClassName, _context.Importer.ImportedAssemblies);
                _lexer.Reset();

                MethodGenerator.BeginMethod(_context.MethodName, resultType, _context.ParameterVariables, _context.LocalVariables, false, string.Empty);
                ParseExpression();
                MethodGenerator.EndMethod();

                bool readOnly = resultType.IsArray || resultType == IrisType.Void;
                if (_context.ErrorCount == 0)
                {
                    _context.Emitter.EndProgram();

                    if (!readOnly)
                    {
                        // As a final step, see if this expression is something that can be assigned
                        // to.  We only support very simple L-Values for assignments so if the syntax
                        // doesn't match exactly, make the result read only.
                        _lexer.Reset();
                        readOnly = !TryParseAsLValue();
                    }
                }

                if (resultType == IrisType.Boolean)
                {
                    // Setting the "BoolResult" flag allows the expression to be used for a
                    // "when true" breakpoint condition.
                    _context.ResultFlags |= DkmClrCompilationResultFlags.BoolResult;
                }

                if (ParsedCallSyntax)
                {
                    // If we parsed call syntax, this expression has the potential to have side
                    // effects.  Setting the PotentialSideEffect flag prevents the debugger from
                    // implicitly evaluating the expression without user interaction.
                    // Instead of implicity evaluating the expression, the debugger will show the
                    // message "This expression has side effects and will not be evaluated"
                    _context.ResultFlags |= DkmClrCompilationResultFlags.PotentialSideEffect;

                    readOnly = true; // Can't modify return value of call
                }

                if (readOnly)
                {
                    _context.ResultFlags |= DkmClrCompilationResultFlags.ReadOnlyResult;
                }
            }
        }
Пример #2
0
        private void MaybeGenerateEntryForSymbol(Symbol symbol)
        {
            if (_context.ArgumentsOnly && symbol.StorageClass != StorageClass.Argument)
            {
                // We are only showing arguments
                return;
            }

            IrisType symbolType = symbol.Type;

            if (symbolType.IsMethod || symbolType == IrisType.Invalid || symbolType == IrisType.Void)
            {
                // This symbol doesn't belong in the Locals window.
                // Don't generate an entry for it.
                return;
            }

            if (symbol.Name.StartsWith("$."))
            {
                // Don't show compiler internal symbols
                return;
            }

            string   methodName = _context.NextMethodName();
            IrisType derefType  = DerefType(symbolType);

            // Emit code for the method to get the symbol value.
            MethodGenerator.BeginMethod(methodName, derefType, _context.ParameterVariables, _context.LocalVariables, entryPoint: false, methodFileName: null);
            EmitLoadSymbol(symbol, SymbolLoadMode.Dereference);
            MethodGenerator.EndMethod();

            // Generate the local entry to pass back to the debug engine
            DkmClrCompilationResultFlags resultFlags = DkmClrCompilationResultFlags.None;

            if (derefType == IrisType.Boolean)
            {
                // The debugger uses "BoolResult" for breakpoint conditions so setting the flag
                // here has no effect currently, but we set it for the sake of consistency.
                resultFlags |= DkmClrCompilationResultFlags.BoolResult;
            }
            else if (derefType.IsArray)
            {
                // Iris doesn't support modification of an array itself
                resultFlags |= DkmClrCompilationResultFlags.ReadOnlyResult;
            }

            string fullName = symbol.Name;

            _context.GeneratedLocals.Add(DkmClrLocalVariableInfo.Create(
                                             fullName,
                                             fullName,
                                             methodName,
                                             resultFlags,
                                             DkmEvaluationResultCategory.Data,
                                             null));
        }
Пример #3
0
        public override void TranslateInput()
        {
            _context.Emitter.BeginProgram(_context.ClassName, _context.Importer.ImportedAssemblies);
            MethodGenerator.BeginMethod(_context.MethodName, IrisType.Void, _context.ParameterVariables, _context.LocalVariables, false, string.Empty);

            // Parse the L-Value.
            // We use a seperate lexer for this because it's part of a different string.
            Symbol lvalue;

            byte[]       buffer = Encoding.Default.GetBytes(_context.AssignmentLValue);
            MemoryStream input  = new MemoryStream(buffer);

            using (StreamReader reader = new StreamReader(input))
            {
                Lexer lvalLexer = Lexer.Create(reader, _context.CompileErrors);
                lvalue = ParseLValue(lvalLexer);
                if (lvalue == null)
                {
                    return; // Parsing the L-Value failed.  (Error message already generated)
                }
            }

            IrisType lhs = lvalue.Type;

            // Parse the R-Value.
            IrisType rhs = ParseExpression();

            if (!Accept(Token.Eof))
            {
                AddErrorAtTokenStart("Unexpected text after expression.");
            }

            // Now finish emitting the code to do the assignment.
            if (rhs != IrisType.Invalid)
            {
                bool hasElementType = false;
                if (lhs.IsByRef || lhs.IsArray)
                {
                    hasElementType = true;
                    lhs            = lhs.GetElementType();
                }

                if (lhs != rhs)
                {
                    AddErrorAtLastParsedPosition("Cannot assign value.  Expression type doesn't match value type");
                }
                else if (hasElementType)
                {
                    if (lvalue.Type.IsArray)
                    {
                        MethodGenerator.StoreElement(lhs);
                    }
                    else
                    {
                        MethodGenerator.Store(lhs);
                    }
                }
                else
                {
                    EmitStoreSymbol(lvalue);
                }
            }

            if (_context.ErrorCount == 0)
            {
                MethodGenerator.EndMethod();
                _context.Emitter.EndProgram();
            }
        }
        protected void ParseProgram()
        {
            string programName = "program";

            if (Accept(Token.KwProgram))
            {
                if (Accept(Token.Identifier))
                {
                    programName = _lexeme;
                }
                else
                {
                    AddErrorAtTokenStart("Expecting program name.");
                }

                Expect(Token.ChrSemicolon);
            }

            _context.Emitter.BeginProgram(programName, _context.Importer.ImportedAssemblies);

            List <Tuple <Variable, FilePosition> > globals = new List <Tuple <Variable, FilePosition> >();

            if (Accept(Token.KwVar))
            {
                ParseVariableList(globals, isArgumentList: false);
                foreach (Tuple <Variable, FilePosition> globalDecl in globals)
                {
                    Variable global = globalDecl.Item1;
                    if (ValidateName(globalDecl.Item2, global.Name, global: true))
                    {
                        Symbol globalSymbol = _symbolTable.Add(global.Name, global.Type, StorageClass.Global);
                        _context.Emitter.DeclareGlobal(globalSymbol);
                    }
                }
            }

            FilePosition blockBegin = _lexer.TokenStartPosition;

            while (!Accept(Token.KwBegin))
            {
                if (Accept(Token.Eof))
                {
                    AddErrorAtLastParsedPosition("Unexpected end of file looking for main block.");
                    return;
                }
                else if (Accept(Token.KwFunction))
                {
                    ParseMethod(isFunction: true);
                }
                else if (Accept(Token.KwProcedure))
                {
                    ParseMethod(isFunction: false);
                }
                else if (Accept(Token.KwVar))
                {
                    AddErrorAtTokenStart("Global variables must be declared before the first function or procedure.");
                    List <Tuple <Variable, FilePosition> > unused = new List <Tuple <Variable, FilePosition> >();
                    ParseVariableList(unused, isArgumentList: false);
                }
                else if (!Accept(Token.ChrSemicolon))
                {
                    AddErrorAtTokenStart("Expecting 'function', 'procedure', or 'begin'.");
                    SkipToNextEnd();
                }

                blockBegin = _lexer.TokenStartPosition;
            }

            // We are now at the main block
            IrisType mainMethod = Procedure.Create(new Variable[0]);
            Symbol   mainSymbol = _symbolTable.OpenMethod("$.main", mainMethod);

            MethodGenerator.BeginMethod(mainSymbol.Name, IrisType.Void, new Variable[0], new Variable[0], true, _context.FilePath);
            MethodGenerator.EmitNonCodeLineInfo(blockBegin.Expand(5 /* Length of "begin" */));

            // Initialize global variables if needed
            foreach (Tuple <Variable, FilePosition> globalDecl in globals)
            {
                InitializeVariableIfNeeded(blockBegin, globalDecl.Item1);
            }

            ParseStatements(Token.KwEnd);

            MethodGenerator.EndMethod();

            Accept(Token.ChrPeriod);
            Expect(Token.Eof);

            _context.Emitter.EndProgram();
        }