public virtual DataType ProcessIdentExpression(IdentExpressionAst identExpression) { var name = identExpression.IdentifierToken.Value; if (!SymbolScope.FindSymbolDeep(name, out Symbol symbol)) { throw new SemanticException($"Symbol {name} not exist"); } if (!(symbol is VariableSymbol variableSymbol)) { throw new SemanticException($"Symbol {name} is not const/var"); } // All check ok if (CodeGenerationEnabled) { // load-variable-addr if (variableSymbol.IsGlobal) { var id = variableSymbol.GlobalVariableBuilder.Id; ExpressionBucket.Add(new object[] { "globa", id }); } else { if (variableSymbol.LocalLocation.IsArgument) { var id = variableSymbol.LocalLocation.Id; if (CurrentFunction.ReturnType != DataType.Void) { id++;// because arg0 is ret val } var instruction = Instruction.Pack("arga", id); instruction.Comment = variableSymbol.Name + " (ident-expr)"; ExpressionBucket.Add(instruction); } else { // 局部变量 var id = variableSymbol.LocalLocation.Id; ExpressionBucket.Add(new object[] { "loca", id }); } } // de-reference ExpressionBucket.Add(Instruction.Pack("load.64")); } return(variableSymbol.Type); }
public IntermediateCodeGenerator(SymbolScope symbolScope) { SymbolScope = symbolScope ?? throw new ArgumentNullException(nameof(symbolScope)); }
public void ProcessFunction(FunctionAst functionAst) { Guard.Against.Null(functionAst, nameof(functionAst)); if (SymbolScope.FindSymbolDeep(functionAst.Name.Value, out Symbol symbol)) { throw new SemanticException($"Symbol already exist: {symbol.Name}, {symbol.GetType()}"); } if (!new[] { "int", "double", "void" }.Contains(functionAst.ReturnType.Value)) { throw new SemanticException($"Bad returning type: {functionAst.ReturnType.Value}"); } var returnType = DataTypeHelper.ParseIntDoubleVoid(functionAst.ReturnType.Value); // Add function to scope var paramTypeList = new List <DataType>(); if (functionAst.HasParams) { foreach (var parameter in functionAst.FunctionParamList.FunctionParams) { var paramType = parameter.Type.Value switch { "int" => DataType.Long, "double" => DataType.Double, _ => throw new SemanticException($"Bad param type: {parameter.Type.Value}") }; paramTypeList.Add(paramType); } } var functionSymbol = new FunctionSymbol(functionAst.Name.Value, returnType, paramTypeList); SymbolScope.AddSymbol(functionSymbol); // register function if (CodeGenerationEnabled) { GlobalBuilder.RegisterFunction(functionSymbol); } // Create scope SymbolScope = SymbolScope.CreateChildScope(); // for testing functionSymbol.BodyBlockScope = SymbolScope; EnterFunctionDefination(functionSymbol); { // register params if (functionAst.HasParams) { foreach (var parameter in functionAst.FunctionParamList.FunctionParams) { var paramType = parameter.Type.Value switch { "int" => DataType.Long, "double" => DataType.Double, _ => throw new SemanticException($"Bad param type: {parameter.Type.Value}") }; var name = parameter.Name.Value; if (SymbolScope.FindSymbolShallow(name, out Symbol _)) { throw new SemanticException($"Exist symbol: {name}"); } // Add to scope var argSymbol = new VariableSymbol(name, false, parameter.IsConstant, paramType); SymbolScope.AddSymbol(argSymbol); if (CodeGenerationEnabled) { CurrentFunction.Builder.RegisterArgument(argSymbol); } } } var canReturn = ProcessBlockStatement(functionAst.BodyBlock, suppressNewScopeCreation: true); if (!canReturn && ReturnCheckEnabled && returnType != DataType.Void) { throw new SemanticException($"Cannot leave function {functionAst.Name.Value}"); } // implecit void returning if (CodeGenerationEnabled && returnType == DataType.Void) { CurrentFunction.Builder.Bucket.Add(new Instructions.Instruction("ret")); } } LeaveFunctionDefination(); SymbolScope = SymbolScope.ParentScope; }
public virtual void ProcessConstDeclarationStatement(ConstDeclarationStatementAst constDeclaration) { var name = constDeclaration.Name.Value; if (SymbolScope.FindSymbolShallow(name, out Symbol existingSymbol)) { throw new SemanticException( $"Cannot const declare because of duplicated name. " + $"Existing symbol type: {existingSymbol.GetType()}"); } if (!new[] { "int", "double" }.Contains(constDeclaration.Type.Value)) { throw new SemanticException($"Type {constDeclaration.Type.Value} should be int or double"); } var declaringType = constDeclaration.Type.Value switch { "int" => DataType.Long, "double" => DataType.Double, _ => throw new Exception("Not Reached") }; var initialExpressionType = ProcessExpression(constDeclaration.ValueExpression); if (declaringType != initialExpressionType) { throw new SemanticException( $"DeclaringType: {declaringType}, InitialExpressionType: {initialExpressionType}"); } // All check ok var symbol = new VariableSymbol(name, !IsInFunction, true, declaringType); SymbolScope.AddSymbol(symbol); if (CodeGenerationEnabled) { if (symbol.IsGlobal) { GlobalBuilder.RegisterGlobalVariable(symbol); symbol.GlobalVariableBuilder.LoadValueInstructions = ExpressionBucket.Pop(); Debug.Assert(symbol.GlobalVariableBuilder.LoadValueInstructions.Count > 0); } else { CurrentFunction.Builder.RegisterLocalVariable(symbol); // load address CurrentFunction.Builder.Bucket.Add(new object[] { "loca", symbol.LocalLocation.Id }); // load init expr CurrentFunction.Builder.Bucket.AddRange(ExpressionBucket.Pop()); // set memory value CurrentFunction.Builder.Bucket.AddSingle("store.64"); } } }
public SymbolScope(SymbolScope parentScope) { ParentScope = parentScope ?? throw new ArgumentNullException(nameof(parentScope)); }
public virtual DataType ProcessAssignExpression(AssignExpressionAst assignExpression) { // IDENT '=' expr // IDENT 是可以赋值的变量,expr是int或者double var name = assignExpression.Identifier.Value; if (!SymbolScope.FindSymbolDeep(assignExpression.Identifier.Value, out Symbol symbol)) { throw new SemanticException($"Symbol name '{name}' not found"); } if (!(symbol is VariableSymbol variableSymbol)) { throw new SemanticException($"Symbol '{name}' is function symbol, cannot assign value"); } if (variableSymbol.IsConstant) { throw new SemanticException($"Symbol '{name}' is constant, cannot assign value"); } var valueType = ProcessExpression(assignExpression.Expression); if (valueType != variableSymbol.Type) { throw new SemanticException( $"Variable '{name}' is type '{variableSymbol.Type}', but expression is '{valueType}'"); } var valueExpressionCode = ExpressionBucket.Pop(); // All check ok if (CodeGenerationEnabled) { // load-variable-addr if (variableSymbol.IsGlobal) { var id = variableSymbol.GlobalVariableBuilder.Id; ExpressionBucket.Add(new object[] { "globa", id }); } else { if (variableSymbol.LocalLocation.IsArgument) { // 函数参数 (+1) var id = variableSymbol.LocalLocation.Id; if (CurrentFunction.ReturnType != DataType.Void) { id++; } var instruction = Instruction.Pack("arga", id); instruction.Comment = variableSymbol.Name + " call-arg"; ExpressionBucket.Add(instruction); } else { // 局部变量 var id = variableSymbol.LocalLocation.Id; ExpressionBucket.Add(new object[] { "loca", id }); } } // value-expr ExpressionBucket.AddRange(valueExpressionCode); // store.64 ExpressionBucket.Add(new Instruction("store.64")); } return(DataType.Void); }
public virtual DataType ProcessCallExpression(CallExpressionAst callExpression) { var name = callExpression.Identifier.Value; if (!SymbolScope.FindSymbolDeep(name, out Symbol symbol)) { throw new SemanticException($"Symbol name '{name}' not found"); } if (!(symbol is FunctionSymbol functionSymbol)) { throw new SemanticException($"Symbol '{name}' is not function, cannot call."); } // ret-space: 如果是stdlibs,不需要预留空间。如果是返回void的,也不用。 if (CodeGenerationEnabled && !IsStdLibCall(functionSymbol.Name) && functionSymbol.ReturnType != DataType.Void) { ExpressionBucket.Add(new object[] { "push", (long)0 }); } var needCount = functionSymbol.ParamTypes.Count; var providedCount = callExpression.HasParams ? callExpression.ParamList.Parameters.Count : 0; if (needCount != providedCount) { throw new SemanticException($"Function '{name}' needs {needCount} param(s)," + $"but provided {providedCount} param(s)"); } // Now, 0:0 or n:n. Check the types when n:n if (needCount != 0) { var providedTypes = new List <DataType>(); foreach (var parameter in callExpression.ParamList.Parameters) { var expressionType = ProcessExpression(parameter); providedTypes.Add(expressionType); } Debug.Assert(functionSymbol.ParamTypes.Count == providedTypes.Count); if (!functionSymbol.IsParamTypeMatch(providedTypes)) { throw new SemanticException($"Call to function '{name}' cannot match param types"); } } // call func id if (CodeGenerationEnabled) { if (!IsStdLibCall(functionSymbol.Name)) { var funcId = functionSymbol.Builder.Id; ExpressionBucket.Add(Instruction.Pack("call", funcId)); } else { // stdlib calls var opcode = StdLibReference[functionSymbol.Name]; Debug.Assert(opcode != null); ExpressionBucket.Add(new Instruction(opcode)); } } return(functionSymbol.ReturnType); }