private void ProcessVariableDeclaration(VariableDeclaration var, IDiagnostics diagnostics) { string id = var.Identifier; var.VariableType = this.ResolveDataType(var.VariableType, diagnostics); if (this.variableBlocks.Peek().Contains(id)) { var diagnostic = new Diagnostic( DiagnosticStatus.Error, MultipleDeclarationsDiagnostic, $"Multiple declarations of variable name {id}", new List <Range> { var.InputRange }); diagnostics.Add(diagnostic); this.exceptions.Add(new NameResolverInternalException($"Multiple declarations of name {id}")); } if (!this.variables.ContainsKey(id)) { this.variables.Add(id, new Stack <VariableDeclaration>()); } this.variables[id].Push(var); this.variableBlocks.Peek().Add(id); }
private DataType ResolveDataType(DataType type, IDiagnostics diagnostics) { switch (type) { case UnresolvedType unresolvedType: if (!this.dataTypes.ContainsKey(unresolvedType.Type)) { var diag = new Diagnostic( DiagnosticStatus.Error, TypeIdentifierErrorDiagnosticsType, $"Unexpected type identifier: '{unresolvedType.Type}'", new List <Range> { unresolvedType.InputRange }); diagnostics.Add(diag); throw new NameResolverException($"unexpected type identifier: {unresolvedType.Type}"); } return(this.dataTypes[unresolvedType.Type]); case UnresolvedArrayType unresolvedArray: var childDataType = this.ResolveDataType(unresolvedArray.Child, diagnostics); return(new ArrayType(childDataType)); case UnresolvedFunctionType unresolved: return(new FunType( argTypes: unresolved.ArgTypes.Select(x => this.ResolveDataType(x, diagnostics)).ToList(), resultType: this.ResolveDataType(unresolved.ResultType, diagnostics))); } return(type); }
private IState GetNextState(KeyValuePair <ILocation, char> currChar, IState currState, IDiagnostics diagnostics) { var location = currChar.Key; var character = currChar.Value; if (character == Constants.EndOfInput) { return(null); } IState newState = this.minimalizedDfa.Transition(currState, character); if (newState != null) { return(newState); } var message = $"Char '{character}' is not from alphabet"; diagnostics.Add(new Diagnostic( DiagnosticStatus.Error, CharNotFromAlphabetDiagnostic, message, new List <Range> { new Range(location, location) })); throw new LexerException(message); }
public Artifacts RunOnInputReader(IInputReader inputReader, IDiagnostics diagnostics) { try { var input = inputReader.Read(); var preprocessed = this.preprocessor.PreprocessInput(input, diagnostics); var tokens = this.lexer.Scan(preprocessed, diagnostics); var tokensFiltered = tokens.Where(x => !KjuAlphabet.Whitespace.Equals(x.Category)); var tree = this.parser.Parse(tokensFiltered, diagnostics); var ast = this.parseTreeToAstConverter.GenerateAst(tree, diagnostics); this.nameResolver.Run(ast, diagnostics); this.typeChecker.Run(ast, diagnostics); this.returnChecker.Run(ast, diagnostics); this.variableAndFunctionBuilder.BuildFunctionsAndVariables(ast); var functionsIR = this.intermediateGenerator.CreateIR(ast); if (!functionsIR.Any(x => x.Key.MangledName == "_ZN3KJU3kjuEv")) { diagnostics.Add(new Diagnostic( DiagnosticStatus.Error, NoEntryPointDiagnosticType, "No kju function", new List <Range> { })); throw new CompilerException("No kju function", new Exception()); } var dataSectionHeader = this.asmHeaderGenerator.GenerateDataSectionHeader(); var dataSection = this.dataTypeLayoutGenerator.GenerateDataLayouts(ast).Prepend(dataSectionHeader); var asmHeader = this.asmHeaderGenerator.GenerateHeader(); var functionsAsm = functionsIR.SelectMany(x => this.functionToAsmGenerator.ToAsm(x.Key, x.Value)) .ToList(); var asm = functionsAsm.Prepend(asmHeader).Concat(dataSection).ToList(); return(new Artifacts(ast, asm)); } catch (Exception ex) when( ex is PreprocessorException || ex is LexerException || ex is ParseException || ex is ParseTreeToAstConverterException || ex is NameResolverException || ex is TypeCheckerException || ex is ReturnCheckerException || ex is FunctionBodyGeneratorException) { throw new CompilerException("Compilation failed.", ex); } }
private void ProcessProgram(Program program, IDiagnostics diagnostics) { this.functionBlocks.Push(new Dictionary <string, List <FunctionDeclaration> >()); this.variableBlocks.Push(new HashSet <string>()); this.structBlocks.Push(new HashSet <string>()); foreach (var fun in program.Functions) { var id = fun.Identifier; if (!this.functions.ContainsKey(id)) { this.functions.Add(id, new Stack <List <FunctionDeclaration> >()); } this.AddToPeek(id, fun); } foreach (var structDecl in program.Structs) { if (this.structs.ContainsKey(structDecl.Name)) { var diagnostic = new Diagnostic( DiagnosticStatus.Error, MultipleDeclarationsDiagnostic, $"Multiple declarations of struct {structDecl.Name}", new List <Range> { structDecl.InputRange }); diagnostics.Add(diagnostic); this.exceptions.Add(new NameResolverInternalException($"Multiple declarations struct {structDecl.Name}")); } this.dataTypes[structDecl.Name] = StructType.GetInstance(structDecl); this.structs[structDecl.Name] = new Stack <StructDeclaration>(); this.structs[structDecl.Name].Push(structDecl); this.structBlocks.Peek().Add(structDecl.Name); } this.functionBlocks.Push(new Dictionary <string, List <FunctionDeclaration> >()); this.variableBlocks.Push(new HashSet <string>()); this.structBlocks.Push(new HashSet <string>()); }
private void ProcessFunctionDeclaration(FunctionDeclaration fun, IDiagnostics diagnostics) { var id = fun.Identifier; fun.ReturnType = this.ResolveDataType(fun.ReturnType, diagnostics); // It is important to do it here, so FunctionDeclaration.ParametersTypesEquals below works correctly for (int i = 0; i < fun.Parameters.Count; i++) { fun.Parameters[i].VariableType = this.ResolveDataType(fun.Parameters[i].VariableType, diagnostics); } if (this.functionBlocks.Peek().ContainsKey(id)) { foreach (var f in this.functionBlocks.Peek()[id]) { if (FunctionDeclaration.ParametersTypesEquals(f, fun)) { var diagnostic = new Diagnostic( DiagnosticStatus.Error, MultipleDeclarationsDiagnostic, $"Multiple declarations of function name {id}", new List <Range> { fun.InputRange }); diagnostics.Add(diagnostic); this.exceptions.Add( new NameResolverInternalException($"Multiple declarations of name {id}")); } } } if (!this.functions.ContainsKey(id)) { this.functions.Add(id, new Stack <List <FunctionDeclaration> >()); } this.AddToPeek(id, fun); this.functionBlocks.Push(new Dictionary <string, List <FunctionDeclaration> >()); this.variableBlocks.Push(new HashSet <string>()); this.structBlocks.Push(new HashSet <string>()); }
private void ProcessVariable(Variable var, IDiagnostics diagnostics) { string id = var.Identifier; if (!this.variables.ContainsKey(id) || this.variables[id].Count == 0) { Diagnostic diagnostic = new Diagnostic( DiagnosticStatus.Error, IdentifierNotFoundDiagnostic, $"No variable of name {id}", new List <Range> { var.InputRange }); diagnostics.Add(diagnostic); this.exceptions.Add(new NameResolverInternalException($"No variable of name {id}")); } else { var.Declaration = this.variables[id].Peek(); } }
private void ProcessUnApplication(UnApplication unapplication, IDiagnostics diagnostics) { var identifier = unapplication.FunctionName; if (!this.functions.ContainsKey(identifier) || this.functions[identifier].Count == 0) { var message = $"No function of name '{identifier}'"; var diagnostic = new Diagnostic( DiagnosticStatus.Error, IdentifierNotFoundDiagnostic, message, new List <Range> { unapplication.InputRange }); diagnostics.Add(diagnostic); this.exceptions.Add(new NameResolverInternalException(message)); } else { unapplication.Candidates = this.GetDeclarationCandidates(identifier); } }
private void ProcessStructDeclaration(StructDeclaration structDeclaration, IDiagnostics diagnostics) { string name = structDeclaration.Name; if (this.structBlocks.Peek().Contains(name)) { var diagnostic = new Diagnostic( DiagnosticStatus.Error, MultipleDeclarationsDiagnostic, $"Multiple declarations of struct {name}", new List <Range> { structDeclaration.InputRange }); diagnostics.Add(diagnostic); this.exceptions.Add(new NameResolverInternalException($"Multiple declarations struct {name}")); } if (this.buildInTypes.Contains(name)) { var diagnostic = new Diagnostic( DiagnosticStatus.Error, TypeIdentifierErrorDiagnosticsType, $"Cannot use builtin type name {name}", new List <Range> { structDeclaration.InputRange }); diagnostics.Add(diagnostic); this.exceptions.Add(new NameResolverInternalException($"Cannot use builtin type name {name}")); } if (!this.structs.ContainsKey(name)) { this.structs.Add(name, new Stack <StructDeclaration>()); } this.structs[name].Push(structDeclaration); this.structBlocks.Peek().Add(name); this.dataTypes[name] = StructType.GetInstance(structDeclaration); var fieldNames = new HashSet <string>(); foreach (var field in structDeclaration.Fields) { var fieldName = field.Name; if (fieldNames.Contains(fieldName)) { var diagnostic = new Diagnostic( DiagnosticStatus.Error, MultipleDeclarationsDiagnostic, $"Multiple declarations of field: {fieldName} in struct: {name}", new List <Range> { structDeclaration.InputRange }); diagnostics.Add(diagnostic); this.exceptions.Add(new NameResolverInternalException($"Multiple field declarations struct {name}")); } fieldNames.Add(fieldName); } foreach (var field in structDeclaration.Fields) { field.Type = this.ResolveDataType(field.Type, diagnostics); } }
RemoveComments(IEnumerable <KeyValuePair <ILocation, char> > input, IDiagnostics diagnostics) { KeyValuePair <ILocation, char>?prev = null; int depth = 0; foreach (KeyValuePair <ILocation, char> c in input) { if (prev?.Value == '/' && c.Value == '*') { if (depth++ == 0) { yield return(new KeyValuePair <ILocation, char>(prev.Value.Key, ' ')); } prev = null; continue; } if (prev?.Value == '*' && c.Value == '/') { if (depth == 0) { diagnostics.Add(new Diagnostic( DiagnosticStatus.Error, UnexpectedCommentEndDiagnosticType, "Unexpected comment end delimiter at {0}", new List <Lexer.Range> { new Lexer.Range(c.Key, c.Key) })); throw new PreprocessorException("Unexpected comment end", c.Key); } prev = null; depth--; continue; } if (depth == 0 && prev.HasValue) { yield return(prev.Value); } prev = c; } if (depth != 0) { diagnostics.Add(new Diagnostic( DiagnosticStatus.Error, UnterminatedCommentDiagnosticType, "Unterminated comment at the end of input", new List <Lexer.Range> { })); throw new PreprocessorException("Non-terminated comment at the end of file", prev?.Key); } if (prev.HasValue) { yield return(prev.Value); } }
public IEnumerable <Token <TLabel> > Scan( IEnumerable <KeyValuePair <ILocation, char> > text, IDiagnostics diagnostics) { using (var it = text.GetEnumerator()) { it.MoveNext(); var currChar = it.Current; var currState = this.minimalizedDfa.StartingState(); currState = this.GetNextState(currChar, currState, diagnostics); ILocation begin = currChar.Key; StringBuilder tokenText = new StringBuilder(); while (currChar.Value != Constants.EndOfInput) { it.MoveNext(); var nextChar = it.Current; IState nextState = this.GetNextState(nextChar, currState, diagnostics); tokenText.Append(currChar.Value); if (nextState == null || this.minimalizedDfa.IsStable(nextState)) { TLabel label = this.minimalizedDfa.Label(currState); Range rng = new Range(begin, nextChar.Key); if (label.Equals(this.noneValue)) { diagnostics.Add(new Diagnostic( DiagnosticStatus.Error, NonTokenDiagnostic, $"Non-token with text '{Diagnostic.EscapeForMessage(tokenText.ToString())}'", new List <Range> { rng })); throw new LexerException($"Non-token at position {rng} with text '{tokenText}'"); } Token <TLabel> ret = new Token <TLabel> { Category = label, InputRange = rng, Text = tokenText.ToString() }; tokenText.Clear(); begin = nextChar.Key; nextState = this.minimalizedDfa.StartingState(); nextState = nextChar.Value == Constants.EndOfInput ? null : this.minimalizedDfa.Transitions(nextState)[nextChar.Value]; yield return(ret); } currChar = nextChar; currState = nextState; } if (begin != currChar.Key) { var message = "Unexpected end of input"; diagnostics.Add(new Diagnostic( DiagnosticStatus.Error, UnexpectedEOFDiagnostic, message, new List <Range> { })); throw new LexerException(message); } } yield return(new Token <TLabel> { Category = this.eof }); }