⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 parser.cs

📁 charp compiler
💻 CS
📖 第 1 页 / 共 5 页
字号:
        Token tOp = m_lexer.GetNextToken();
        BinaryExp.BinaryOp op = ConvertToBinaryOp(tOp);
        
        // @todo - Check that it's a valid overloadable op...
        
        // Parse parameters. Expect 2, both values (not ref/out)
        ParamVarDecl [] arParams = ParseParamList();
        if (arParams.Length != 2)
            ThrowError(E_BadParamListOnOps(typeReturn.Location, "Must have 2 parameters"));

        
        for(int i = 0; i < arParams.Length; i++)
        {   
            if (arParams[i].Flow != EArgFlow.cIn)
                ThrowError(E_BadParamListOnOps(arParams[i].Location, "Parameter " + i + " can't be ref/out"));
        }
            
        
        // Read method body. This will include the '{' ... '}'    
        BlockStatement block = ParseStatementBlock();
        
        // Allocate the method decl
        MethodDecl nodeMethod = new MethodDecl(
            op, 
            typeReturn, 
            arParams, 
            block
        );
            
        return nodeMethod;            
        
    }

//-----------------------------------------------------------------------------
// Do a partial parse of the method decl (includes ctor), 
// Pass in the parameters that we've already parsed, which is everything 
// before the first '('. 
//
// ** Rules **
// methoddecl -> attrs type id '(' paramlist ')' '{' statementlist '}'
// methoddecl -> attrs type id '(' paramlist ')' ';'   // if abstract
//-----------------------------------------------------------------------------
    protected MethodDecl PartialParseMethodDecl(
        Modifiers mods, 
        TypeSig typeReturn,
        Identifier stMemberName,
        Genre genre // applies additional restrictions
    )
    {   
    // We should have already parsed the 'attrs type id'. So continue with param list
        
        ParamVarDecl [] arParams = ParseParamList();
        
        // Structs can't define a default ctor
        if ((genre == Genre.cStruct) && (typeReturn == null) && (arParams.Length == 0))
        {
            ThrowError(E_NoDefaultCtorForStructs(m_lexer.PeekNextToken().Location));
        }
        

        CtorChainStatement chain  = null;
    // If this is a constructor, then we can chain it
    // ctordecl -> mods type id '(' param_list ')' ':' (this|base) '(' param_list ')' '{' statementlist '}'
    // ctor can't be abstract / virtual. Can be static
        if (typeReturn == null)
        {   
            Token t = m_lexer.PeekNextToken();
            if (genre == Genre.cInterface)
            {
                ThrowError(E_NoCtorOnInterface(t.Location));
            }        
            
            if (t.TokenType == Token.Type.cColon)
            {                
                ConsumeNextToken();
                // Currently, 'base' & 'this' are just identifiers, not specific tokens
                Identifier id = this.ReadExpectedIdentifier();
                Exp [] arParams2 = ParseExpList();

                CtorChainStatement.ETarget eTarget = (CtorChainStatement.ETarget) (-1);
                
                if (id.Text == "this")
                    eTarget = CtorChainStatement.ETarget.cThis;
                else if (id.Text == "base")
                {
                    if (genre == Genre.cStruct)
                    {
                        ThrowError(E_NoBaseChainForStructs(id.Location));
                    }
                    eTarget = CtorChainStatement.ETarget.cBase;
                }
                else 
                {
                    ThrowError(E_BadCtorChain(id));
                }

                chain = new CtorChainStatement(eTarget, arParams2);
            } 
            else 
            {
                // If no explicit ctor chain, then we still have an implicit "base ()"
                // (except for static ctors, which can't be chained)
                if (!mods.IsStatic && (genre == Genre.cClass))                
                {                
                    chain = new CtorChainStatement();
                }
            }

            // Static ctors can't be chained
            if (chain != null)
            {
                if (mods.IsStatic)                
                {
                    ThrowError(E_NoChainForStaticCtor(stMemberName.Location));
                }
            }
        }


    // Parse body
        BlockStatement block = null;

        if (mods.IsAbstract)        
        {
        // For abstract methods, no body. Just end with a ';'
            ReadExpectedToken(Token.Type.cSemi);        
        } else 
        {        
        // Read method body. This will include the '{' ... '}'    
            block = ParseStatementBlock();
        }


        if (typeReturn == null)
        {
            if (mods.IsAbstract | mods.IsVirtual | (block == null))            
            {
                ThrowError(E_NoAbstractCtor(stMemberName));
            }
        }
        
        // Allocate the method decl
        MethodDecl nodeMethod = new MethodDecl(
            stMemberName, 
            typeReturn, 
            arParams, 
            block,
            mods);

        // If we have a chain, inject it into the statements
        if (chain != null)
        {
            nodeMethod.Body.InjectStatementAtHead(chain);
            chain.FinishInit(nodeMethod);
        }

        return nodeMethod;
    }
#endregion Parse Declarations

#region Parse Statements
//-----------------------------------------------------------------------------
// Parse a scope (includes statement list & declaration)
// The parser will separate out local declarations from statements and
// return 2 separate arrays.
// It will also convert constructs like "int x = 3" to "int x; x = 3"
//
// ** Rules ***
// BlockStatement-> '{' (decl | statement)* '}'
// statement->
//      ObjExp '.' id '(' explist ')' ';'   // method call
//      return [ exp ] ';'                  // return statement (w/ optional return expression)
//      BlockStatement                      // blocks can be nested
//      
// decl ->
//      TypeSig id ';'              // declare a local variable
//      TypeSig id '=' exp ';'      // declare a local and do an assignment.
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Wrapper when we expect a statement
//-----------------------------------------------------------------------------
    protected Statement ParseStatement()
    {
        Statement s;
        LocalVarDecl v;
                
        ParseStatementOrLocal(out s, out v);        
        Debug.Assert(v == null);
        
        
        
        return s;
    }

//-----------------------------------------------------------------------------
// Helper to parse array decls.
// For arrays, leftmost [] is the outermost
// So X[][,,][,] is 1d of 3d of 2d of X
// Because this is left to right (and not right to left), we have to be
// stack based / recursive (instead of an iterative while)
// 
// sigElemType is the type of the non-array portion (X in the above example)
// Note that if this isn't an array type, we'll just return sigElemType
//-----------------------------------------------------------------------------
    NonRefTypeSig ParseOptionalArrayDecl(NonRefTypeSig sigElemType)
    {
        Token t = m_lexer.PeekNextToken();
        
        if (t.TokenType == Token.Type.cLRSquare)
        {
            ConsumeNextToken();
            
            int dim = t.Dimension;
            NonRefTypeSig sig = ParseOptionalArrayDecl(sigElemType);
            sig = new ArrayTypeSig(sig, dim);
            
            string stTest = sig.ToString();
            
            return sig;
            
        } else {
            return sigElemType;
        }
    }
        
//-----------------------------------------------------------------------------
// Parse a single statement or local var decl (we can't tell which yet)
// Note that may be statement may be a block (which is just fine)
// for a construct like 'int x = 3' (decl & assignment), we'll yeild
// both s & v. Else the out params will be null if we don't have them.
//-----------------------------------------------------------------------------
    protected void ParseStatementOrLocal(out Statement s, out LocalVarDecl v)
    {
        // Wrap the worker to ensure that we have proper line number info
        FileRange f = BeginRange();
        
        // Do the real work
        ParseStatementOrLocal_Helper(out s, out v);
        
        if (s != null)
        {
            s.SetLocation(EndRange(f));
        }
    }
    
    // Do the real work
    protected void ParseStatementOrLocal_Helper(out Statement s, out LocalVarDecl v)
    {   
        s = null;
        v = null;
        
        // For each statement, we know which type based off the first token.
        // Expect for an identifier, in which case it could be a few things.
        Token t = m_lexer.PeekNextToken();
        
        #if false
        // Skip past any ';' (as empty statements)
        while(t.TokenType == Token.Type.cSemi)
        {
            ConsumeNextToken();
            t = m_lexer.PeekNextToken();            
        }
        #endif
                       
        if (IsStartOfExp(t))
        {
            FileRange f = BeginRange();
            
            // This could be either an expression or a type
            Exp e = ParseExp();
            t = m_lexer.PeekNextToken();

            
            // Case 1 - Var declaration:
            // If an identifier follows, then we just read a type and this is
            // a var declaration:
            // Type id ';'
            // Type id '=' exp ';'
            if (t.TokenType == Token.Type.cId)
            {
                TypeSig tSig  = this.ConvertExpToType(e);

                Identifier id = ReadExpectedIdentifier();
                
                v = new LocalVarDecl(id, tSig);
                                
                // Check for optional assignment (if there's an '=' after the name)
                Token t3 = m_lexer.PeekNextToken();
                if (t3.TokenType == Token.Type.cAssign)
                {
                    ConsumeNextToken();                     // '='
                    Exp eRHS = ParseExp();                  // exp                
                    ReadExpectedToken(Token.Type.cSemi);    // ';'
                    
                    SimpleObjExp oleft = new SimpleObjExp(id);
                    StatementExp se = new AssignStmtExp(oleft, eRHS);
                    s = new ExpStatement(se);
                    
                    se.SetLocation(EndRange(f));
                } else {                
                    ReadExpectedToken(Token.Type.cSemi);    // ';'
                }


                
                return;
            } // end decl case

            // Case 2 - label declaration
            else if (t.TokenType == Token.Type.cColon)
            {                
                SimpleObjExp o2 = e as SimpleObjExp;
                if (o2 != null)
                {
                    ConsumeNextToken(); // ':'
                    s = new LabelStatement(o2.Name);
                    return; // skip reading a ';'
                } 
                
                ThrowError(new ParserErrorException(Code.cBadLabelDef, t.Location, 
                    "Bad label definition (labels must be a single identifier)"));                                
            } // end case for label decls
                        
            // Expect a StatementExp
            else if (t.TokenType == Token.Type.cSemi) {
                ReadExpectedToken(Token.Type.cSemi);
                
                // Else we must be a StatementExp
                StatementExp se = e as StatementExp;
                if (se == null)
                    //this.ThrowError_ExpectedStatementExp(e.Location);
                    ThrowError(E_ExpectedStatementExp(e.Location));
                
                se.SetLocation(EndRange(f));
                s = new ExpStatement(se);            
                return;
            }
    
            ThrowError(E_UnexpectedToken(t));
        } // end start of expressions
        
        switch(t.TokenType)
        {
        // Empty statement
        case Token.Type.cSemi:
            ConsumeNextToken();
            s = new EmptyStatement();
            break;

        // Return -> 'return' ';'
        //         | 'return' exp ';'
        case Token.Type.cReturn:
            {
                ConsumeNextToken();
                
               

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -