Exemple #1
0
        public virtual DataType ProcessGoodFactor(GoodFactorAst goodFactor)
        {
            Guard.Against.Null(goodFactor, nameof(goodFactor));
            // { - } strong_factor
            // 检查能否取符号

            var strongFactorType = ProcessStrongFactor(goodFactor.StrongFactor);

            if (goodFactor.IsNegative && !DataTypeHelper.IsLongOrDouble(strongFactorType))
            {
                throw new SemanticException($"{strongFactorType} cannot be negative");
            }

            if (CodeGenerationEnabled)
            {
                if (goodFactor.IsNegative)
                {
                    Debug.Assert(DataTypeHelper.IsLongOrDouble(strongFactorType));
                    var negativeOperation = "neg." + DataTypeHelper.Suffix(strongFactorType);
                    ExpressionBucket.AddSingle(negativeOperation);
                }
            }

            return(strongFactorType);
        }
        public void ProcessWhileStatement(WhileStatementAst whileStatement)
        {
            Guard.Against.Null(whileStatement, nameof(whileStatement));

            var conditionType = ProcessExpression(whileStatement.ConditionExpression);

            if (!(conditionType == DataType.Bool ||
                  conditionType == DataType.Double ||
                  conditionType == DataType.Long))
            {
                throw new SemanticException(
                          $"While condition should be of bool, double or long type. Provided: {conditionType}");
            }

            var doneLabel = new Instruction("nop");

            var startLabel = new Instruction("nop");

            if (CodeGenerationEnabled)
            {
                CurrentFunction.Builder.Bucket.Add(startLabel);
            }

            // cond-expr
            if (CodeGenerationEnabled)
            {
                CurrentFunction.Builder.Bucket.AddRange(ExpressionBucket.Pop());
            }

            // jump(if false) to done
            if (CodeGenerationEnabled)
            {
                CurrentFunction.Builder.Bucket.Add(new object[] { "br.false", doneLabel });
            }

            // # while-block
            EnterWhileDefination(new Builders.WhileBuilder(CurrentWhile, startLabel, doneLabel));

            ProcessBlockStatement(whileStatement.WhileBlock);

            LeaveWhileDefination();

            // jmp .START
            if (CodeGenerationEnabled)
            {
                CurrentFunction.Builder.Bucket.Add(Instruction.Pack("br", startLabel));
            }

            // .DONE:nop
            if (CodeGenerationEnabled)
            {
                CurrentFunction.Builder.Bucket.Add(doneLabel);
            }
        }
        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);
        }
Exemple #4
0
        public virtual DataType ProcessFactor(FactorAst factor)
        {
            var firstType = ProcessGoodFactor(factor.GoodFactor);

            if (factor.AsTypeList.Count == 0)
            {
                return(firstType);
            }

            if (!DataTypeHelper.IsLongOrDouble(firstType))
            {
                throw new SemanticException($"First type '{firstType}' is not double or int");
            }

            var type = firstType;

            foreach (var a in factor.AsTypeList)
            {
                DataType t2;
                switch (a.TypeToken.Value)
                {
                case "int":
                    t2 = DataType.Long;
                    break;

                case "double":
                    t2 = DataType.Double;
                    break;

                default:
                    throw new SemanticException($"Wrong type cast: {a.TypeToken.Value}");
                }

                if (CodeGenerationEnabled)
                {
                    if (type != t2)
                    {
                        var src = DataTypeHelper.Suffix(type);
                        var dst = DataTypeHelper.Suffix(t2);

                        ExpressionBucket.AddSingle(src + "to" + dst);
                    }
                }

                type = t2;
            }

            return(type);
        }
Exemple #5
0
        public virtual DataType ProcessWeakTerm(WeakTermAst weak)
        {
            // Remember to assert each op is +|-
            var firstType = ProcessTerm(weak.Term);

            if (weak.OpTerms.Count == 0)
            {
                return(firstType);
            }

            if (!DataTypeHelper.IsLongOrDouble(firstType))
            {
                throw new SemanticException($"first type '{firstType}' should be int or double");
            }

            char suffix = DataTypeHelper.Suffix(firstType);

            foreach (var(op, term) in weak.OpTerms)
            {
                Debug.Assert(op.Value == Lexical.Tokens.Operator.Plus ||
                             op.Value == Lexical.Tokens.Operator.Minus);

                var termType = ProcessTerm(term);
                if (termType != firstType)
                {
                    throw new SemanticException(
                              $"Term type '{termType}' should be equal to first type '{firstType}'");
                }

                if (CodeGenerationEnabled)
                {
                    if (op.Value == Lexical.Tokens.Operator.Plus)
                    {
                        ExpressionBucket.AddSingle("add." + suffix);
                    }
                    else
                    {
                        ExpressionBucket.AddSingle("sub." + suffix);
                    }
                }
            }

            // list check ok
            return(firstType);
        }
Exemple #6
0
        public virtual DataType ProcessTerm(TermAst term)
        {
            var firstType = ProcessFactor(term.Factor);

            if (term.OpFactors.Count == 0)
            {
                return(firstType);
            }

            if (!DataTypeHelper.IsLongOrDouble(firstType))
            {
                throw new SemanticException($"First factor type {firstType} is not int or double");
            }

            char suffix = DataTypeHelper.Suffix(firstType);

            foreach (var(op, factor) in term.OpFactors)
            {
                Debug.Assert(op.Value == Lexical.Tokens.Operator.Mult ||
                             op.Value == Lexical.Tokens.Operator.Divide);

                var factorType = ProcessFactor(factor);
                if (factorType != firstType)
                {
                    throw new SemanticException($"Factor type '{factorType}' should equal to first type '{firstType}'");
                }

                if (CodeGenerationEnabled)
                {
                    if (op.Value == Lexical.Tokens.Operator.Mult)
                    {
                        ExpressionBucket.AddSingle("mul." + suffix);
                    }
                    else
                    {
                        ExpressionBucket.AddSingle("div." + suffix);
                    }
                }
            }

            // list check ok
            return(firstType);
        }
        public virtual DataType ProcessLiteralExpression(LiteralExpressionAst literalExpression)
        {
            if (literalExpression.Literal is UInt64LiteralToken intLiteral)
            {
                if (CodeGenerationEnabled)
                {
                    ExpressionBucket.Add(new object[] { "push", (long)intLiteral.Value });
                }
                return(DataType.Long);
            }
            if (literalExpression.Literal is DoubleLiteralToken doubleLiteral)
            {
                if (CodeGenerationEnabled)
                {
                    ExpressionBucket.Add(new object[] { "push", doubleLiteral.Value });
                }
                return(DataType.Double);
            }
            if (literalExpression.Literal is StringLiteralToken stringLiteral)
            {
                // 字符串应该存全局变量,并把地址(划掉)应该把全局变量号放在栈上
                if (CodeGenerationEnabled)
                {
                    var id = GlobalBuilder.RegisterStringConstant(stringLiteral.Value);

                    ExpressionBucket.Add(Instruction.Pack("push", (long)id));
                }

                return(DataType.String);
            }
            if (literalExpression.Literal is CharLiteralToken charLiteral)
            {
                if (CodeGenerationEnabled)
                {
                    ExpressionBucket.Add(new object[] { "push", (long)charLiteral.Value });
                }

                return(DataType.Long);
            }
            throw new ArgumentException($"Unknown literal token type: {literalExpression.GetType()}");
        }
        public virtual void ProcessExpressionStatement(ExpressionStatementAst expressionStatement)
        {
            // 表达式语句由 表达式 后接分号组成。表达式如果有值,值将会被丢弃。

            var expressionReturnType = ProcessExpression(expressionStatement.Expression);

            // 因为表达式还在临时bucket里面,所以需要pop出来放在函数bucket里面
            if (CodeGenerationEnabled)
            {
                CurrentFunction.Builder.Bucket.AddRange(ExpressionBucket.Pop());
            }

            // 代码生成,如果不是返回void,则丢弃栈顶的值
            if (CodeGenerationEnabled)
            {
                if (expressionReturnType != DataType.Void)
                {
                    CurrentFunction.Builder.Bucket.AddSingle("pop");
                }
            }
        }
        public void ProcessReturnStatement(ReturnStatementAst returnStatement)
        {
            Guard.Against.Null(returnStatement, nameof(returnStatement));
            // return_stmt -> 'return' expr? ';'
            // 无返回值 - 有返回值

            if (!IsInFunction)
            {
                throw new SemanticException($"Cannot return out side of function defination");
            }

            var sessId = Guid.NewGuid().ToString()
            ;

            // load-retval-addr
            if (CodeGenerationEnabled && CurrentFunction.ReturnType != DataType.Void)
            {
                var instruction = Instruction.Pack("arga", 0);
                instruction.Comment = "load retval addr " + sessId;
                CurrentFunction.Builder.Bucket.Add(instruction);
            }

            DataType actualReturnType;

            if (returnStatement.ReturnExpression != null)
            {
                actualReturnType = ProcessExpression(returnStatement.ReturnExpression);
            }
            else
            {
                actualReturnType = DataType.Void;
            }

            if (actualReturnType != CurrentFunction.ReturnType)
            {
                throw new SemanticException(
                          $"Should return {CurrentFunction.ReturnType}, but return {actualReturnType}");
            }

            // returning-expr;
            if (actualReturnType == DataType.Void)
            {
                Debug.Assert(ExpressionBucket.InstructionList.Count == 0);
            }

            if (CodeGenerationEnabled)
            {
                var exprCode = ExpressionBucket.Pop();
                exprCode.ForEach(p => p.Comment += " " + sessId);
                CurrentFunction.Builder.Bucket.AddRange(exprCode);
            }

            // write-retval
            if (CodeGenerationEnabled && CurrentFunction.ReturnType != DataType.Void)
            {
                if (CodeGenerationEnabled)
                {
                    CurrentFunction.Builder.Bucket.Add(new Instruction("store.64"));
                }
            }

            // ret
            if (CodeGenerationEnabled)
            {
                CurrentFunction.Builder.Bucket.Add(new Instruction("ret")
                {
                    Comment = " " + sessId
                });
            }
        }
        public bool ProcessIfStatement(IfStatementAst ifStatement)
        {
            // 能脱离函数的充要条件:
            // 1. 不能只有if, 要有else。只有if 相当于 可能脱离。“可能”视为0.
            // 2. if-block可以脱离 && else也可以脱离

            Guard.Against.Null(ifStatement, nameof(ifStatement));
            // if_stmt -> 'if' expr block_stmt ('else' (block_stmt | if_stmt))?

            var conditionType = ProcessExpression(ifStatement.ConditionExpression);

            if (!(conditionType == DataType.Bool ||
                  conditionType == DataType.Double ||
                  conditionType == DataType.Long))
            {
                throw new SemanticException(
                          $"If.Condition should be of bool,double or long type. Provided: {conditionType}");
            }


            // codegen: cond-expr
            if (CodeGenerationEnabled)
            {
                CurrentFunction.Builder.Bucket.AddRange(ExpressionBucket.Pop());
            }

            bool canReturn1 = false;
            bool canReturn2 = false;

            if (ifStatement.HasElseAndFollowing)
            {
                var else0 = new Instruction("nop");
                var done0 = new Instruction("nop");

                // jmp-if-false .ELSE0
                if (CodeGenerationEnabled)
                {
                    CurrentFunction.Builder.Bucket.Add(new object[] { "br.false", else0 });
                }

                // if-block
                canReturn1 = ProcessBlockStatement(ifStatement.BlockStatement);

                // jmp .DONE0
                if (CodeGenerationEnabled)
                {
                    CurrentFunction.Builder.Bucket.Add(new object[] { "br", done0 });
                }

                // .ELSE0: nop
                if (CodeGenerationEnabled)
                {
                    CurrentFunction.Builder.Bucket.Add(else0);
                }

                // else-block
                if (ifStatement.FollowingIf != null)
                {
                    // if-else-if
                    canReturn2 = ProcessIfStatement(ifStatement.FollowingIf);
                }
                else
                {
                    // if-else
                    canReturn2 = ProcessBlockStatement(ifStatement.FollowingBlock);
                }

                // .DONE0: nop
                if (CodeGenerationEnabled)
                {
                    CurrentFunction.Builder.Bucket.Add(done0);
                }

                return(canReturn1 && canReturn2);
            }
            else
            {
                var doneInstruction = new Instruction("nop");
                if (CodeGenerationEnabled)
                {
                    CurrentFunction.Builder.Bucket.Add(new object[] { "br.false", doneInstruction });
                }

                // if-block
                canReturn1 = ProcessBlockStatement(ifStatement.BlockStatement);

                // .DONE
                if (CodeGenerationEnabled)
                {
                    CurrentFunction.Builder.Bucket.Add(doneInstruction);
                }
            }

            return(false);
        }
        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 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);
        }
Exemple #14
0
        public virtual DataType ProcessOperatorExpression(OperatorExpressionAst operatorExpression)
        {
            // 注意 https://c0.karenia.cc/c0/expr.html 参数类型必须是数值。
            // 所以如果有比较符号,那么它们都得是数值

            var firstType = ProcessWeakTerm(operatorExpression.WeakTerm);

            if (operatorExpression.OpTerms.Count == 0)
            {
                return(firstType);
            }

            if (operatorExpression.OpTerms.Count > 1)
            {
                throw new SemanticException($"List count >1");
            }

            if (!DataTypeHelper.IsLongOrDouble(firstType))
            {
                throw new SemanticException($"List is not empty, first type '{firstType}' should be int or double");
            }

            var(op, weak) = operatorExpression.OpTerms[0];
            Debug.Assert(op.IsCompare);

            var weakTermType = ProcessWeakTerm(weak);

            if (weakTermType != firstType)
            {
                throw new SemanticException(
                          $"A weak term '{weakTermType}' in list not matching first type '{firstType}'");
            }

            // Check ok. Now comparing.
            var typec = DataTypeHelper.Suffix(firstType);

            if (CodeGenerationEnabled)
            {
                // first do cmp, approx. (a-b)
                ExpressionBucket.AddSingle("cmp." + typec);

                switch (op.Value)
                {
                case Operator.GreaterThan:
                    ExpressionBucket.AddSingle("set.gt");
                    break;

                case Operator.LessThan:
                    ExpressionBucket.AddSingle("set.lt");
                    break;

                case Operator.GreaterEqual:
                    // >= equivalent to (not <)
                    ExpressionBucket.AddSingle("set.lt");
                    ExpressionBucket.AddSingle("not");
                    break;

                case Operator.LessEqual:
                    // <= equivalent to (not >)
                    ExpressionBucket.AddSingle("set.gt");
                    ExpressionBucket.AddSingle("not");
                    break;

                case Operator.Equal:
                    ExpressionBucket.AddSingle("not");
                    break;

                case Operator.NotEqual:
                    // if not equal, a-b is not 0. (not 0 is true)
                    break;

                default:
                    throw new Exception("Not Reached");
                }
                ;
            }

            return(DataType.Bool);
        }