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; } } }
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)); }
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(); }