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

📄 parser.cs

📁 charp compiler
💻 CS
📖 第 1 页 / 共 5 页
字号:
//-----------------------------------------------------------------------------
// Manual Recursive Descent parser 
// We can get away with this because the vast majority of 
// Blue's syntax is predictive. We always know what we're looking for.
// The only semi-complicated thing is arithmetic expressions.
//
// Look at the ILexer interface to know what the parser has to deal with here.
// The parser can only get the current token (which consumes that token),
// and peek at the next token (which doesn't consume the token).
//
// Generally, by using ILexer.Peek alot, we can see what's coming in the 
// token stream and know what to expect. Thus we can delegate to the proper
// parse function.
//-----------------------------------------------------------------------------

using System.Diagnostics;
using System.Collections;
using AST;
//using ErrorLog = Blue.Utilities.ErrorLog;
using Log = Blue.Log;
using IParser = Blue.Public.IParser;
using ILexer = Blue.Public.ILexer;

namespace ManualParser
{

#region Helper classes
#if false
//-----------------------------------------------------------------------------
// Explanation of how we do Expression parsing
//-----------------------------------------------------------------------------
Class to help parse a Left-Associative binary expression
E -> E + T | T
But that can't be parsed recursive descent because it's infinite recursion
So we transform it into:
E -> T1 E'
E' -> + T2 E' | {}
The transformation preserves meaning and can be done recursive descent.

Now this still produces a right-recursive tree, we have to create a left recursive tree.
So when we parse E', we pass in T1 from the parent. And then E' forms a BinaryOp
of T1+T2 and passes that into it's E'.
This builds a left-recursive AST. E' then propagates the tree up through return values.
#endif
#endregion

//-----------------------------------------------------------------------------
// Manual Parser
//-----------------------------------------------------------------------------
/// <summary>
/// The primary parser implementation. Convert a token stream for a source file 
/// obtained by an <see cref="Blue.Public.ILexer"/> into a parse tree.
/// Parse errors are handled by throwing <see cref="ManualParser.Parser.ParserErrorException"/>
/// </summary>
public class Parser : IParser
{
#region Construction
//-----------------------------------------------------------------------------
// Initialize with a lexer to provide the token stream
//-----------------------------------------------------------------------------
    public Parser(ILexer lexer)
    {
        m_lexer = lexer;        
    }
#endregion
    
    protected ILexer m_lexer;

#region Errors   
//-----------------------------------------------------------------------------
// When we get a parser error, we want to throw an exception
// This is really just a way to handle control flow within the parser. This
// exception should never get out of the parser.
//-----------------------------------------------------------------------------

    /// <summary>
    /// ParserErrorException represents parse errors due to bad user-input.
    /// </summary>
    private class ParserErrorException : ErrorException
    {
        internal ParserErrorException(Parser.Code c, FileRange location, string s) : 
            base (c, location, s)
        {
        // All Parser errors will come through this body.
        }
    }       
    
     
//-----------------------------------------------------------------------------
// Error handling
//-----------------------------------------------------------------------------

    /// <summary>
    /// Syntax error codes specific to Parser 
    /// </summary>    
    internal enum Code
    {
        cUnexpectedToken,           // we don't know what we wanted, but we didn't like what we got
        cExpectedDiffToken,         // we know what we wanted and didn't get it
        
       // cIllegalClassMemberDecl,  // We're trying to declare something illegal in our class
        cMissingRetType,            // something bad about the ctor declaration
        cBadLabelDef,               // supposed to define a label (really a misuse of a ':')
        cAccessorAlreadyDefined,    // Property accessor (get | set) already defined
        cMissingAccessor,           // Property/Indexer must have at least 1 accessor

        cNoAbstractCtor,            // Constructors can't be abstract
        cBadCtorChain,              // tried to chain to other than 'this' or 'base'
        cNoChainForStaticCtor,      // static ctors can't be chained,
        cNoBaseChainForStructs,     // Struct ctor decls can't chain to a base
        cNoDefaultCtorForStructs,   // structs can't have a default ctor
                
        cExpectedStatementExp,      // Expected a statement expression
        cBadForInitializer,         // the initializer in the for-loop is bad
        
        cDuplicateModifier,         // Modifiers can't be duplicated
        cIllegalModifiers,          // modifiers on something it shouldn't be on
        
        cNoCtorOnInterface,         // Intefaces can't define constructors
        
        cBadModsOnOps,              // Overloaded operators must be public & static
        cBadParamListOnOps,         // Bad parameter list for an overloaded operator
    }
    
    // Convenience helper so that we don't have to keep qualifying StdErrorLog.
    static private void ThrowError(ParserErrorException e)
    {
        Blue.Driver.StdErrorLog.ThrowError(e);
    }
    
    static private void PrintError(ParserErrorException e)
    {
        Blue.Driver.StdErrorLog.PrintError(e);
    }        
        
    // Perhaps the most general syntax error
    // We don't know what we wanted, but we didn't like what we got
    //protected void ThrowError_UnexpectedToken(Token tokenActual)
    ParserErrorException E_UnexpectedToken(Token tokenActual)
    {
        return new ParserErrorException(        
            Code.cUnexpectedToken, 
            tokenActual.Location,
            "Unexpected token '"+tokenActual.ToString() + "'"
        );    
    }
        
    // We expected a specific type of token and we got something else
    //protected void ThrowError_UnexpectedToken(Token tokenActual, Token.Type typeExpected)
    ParserErrorException E_UnexpectedToken(Token tokenActual, Token.Type typeExpected)
    {
        return new ParserErrorException(        
            Code.cExpectedDiffToken, 
            tokenActual.Location,
            "Expected '" + typeExpected.ToString() + "', but got token '"+tokenActual.ToString() + "'"
        );    
    }
    
    
    // We expected one token out of a possible set, but got something different
    //protected void ThrowError_UnexpectedToken(Token tokenActual, Token.Type [] arTypeExpected)
    ParserErrorException E_UnexpectedToken(Token tokenActual, Token.Type e1, Token.Type e2)
    {
        return E_UnexpectedToken(tokenActual, new Token.Type[] {e1, e2} );
    }
    
    ParserErrorException E_UnexpectedToken(Token tokenActual, Token.Type e1, Token.Type e2, Token.Type e3)
    {
        return E_UnexpectedToken(tokenActual, new Token.Type[] {e1, e2, e3} );
    }
        
    ParserErrorException E_UnexpectedToken(Token tokenActual, Token.Type [] arTypeExpected)
    {
        string stExpected = "";
        foreach(Token.Type t in arTypeExpected)
        {
            stExpected += t.ToString() + " ";            
        }
        
        return new ParserErrorException(        
            Code.cExpectedDiffToken, 
            tokenActual.Location,
            "Expected one of {" + stExpected + "}, but got token '"+tokenActual.ToString() + "'"
        );    
    }
 
    // Bad chain target for a constructor
    //protected void ThrowError_BadCtorChain(Identifier idName)
    ParserErrorException E_BadCtorChain(Identifier idName)
    {
        return new ParserErrorException(
            Code.cBadCtorChain,
            idName.Location,
            "Must specify either 'this' or 'base' in constructor chain, not '" + idName.Text + "'"
        );
    }

    // Static constructors can't be chained.
    ParserErrorException E_NoChainForStaticCtor(FileRange location)
    {
        return new ParserErrorException(
            Code.cNoChainForStaticCtor,
            location,
            "Static constructors can't chain to another constructor"
        );
    }

    // fIsGet - true if a 'get' accessor, false if a 'set accessor
    // idName - name of the culrprit property   
    //protected void ThrowError_AccessorAlreadyDefined(Identifier idName, bool fIsGet)
    ParserErrorException E_AccessorAlreadyDefined(Identifier idName, bool fIsGet)
    {
        return new ParserErrorException(
            Code.cAccessorAlreadyDefined,
            idName.Location,
            "Property '" + idName.Text + "' can't have multiple '" + (fIsGet ? "get" : "set") + "' accessors."
        );            
    }
    
    //protected void ThrowError_MissingAccessor(Identifier idName)
    ParserErrorException E_MissingAccessor(Identifier idName)
    {
        return new ParserErrorException(
            Code.cMissingAccessor,
            idName.Location,
            "Property or Indexer '" + idName.Text + "' must have at least 1 accessor."
        );
    }

    ParserErrorException E_NoAbstractCtor(Identifier idName)
    //protected void ThrowError_NoAbstractCtor(Identifier idName)
    {
        return new ParserErrorException(
            Code.cNoAbstractCtor,
            idName.Location,
            "Constructors can't be abstract and must have a body"
        );
    }
    
    // Check for the corresponding error
    protected void CheckError_UnexpectedToken(Token tokenActual, Token.Type [] arTypeExpected)
    {
        foreach(Token.Type t in arTypeExpected)
        {
            if (tokenActual.TokenType == t)
                return;
        }
        ThrowError(E_UnexpectedToken(tokenActual, arTypeExpected));
        //ThrowError_UnexpectedToken(tokenActual, arTypeExpected);
    }
    
    // Check that eActual only has the modifiers from a certain set (eAllowed),
    // If not, print an error listing all illegal modifiers
    protected void CheckError_LegalModifiers(
        FileRange location, 
        string stTargetHint,  // "class", "method", "property", "interface", etc...
        AST.Modifiers eActual,
        AST.Modifiers eAllowed
    )
    {
        if (eActual != eAllowed)
            ThrowError(
                new ParserErrorException(
                    Code.cIllegalModifiers,
                    location,
                    "Illegal modifiers on a '" + stTargetHint + "'"
                )
            );
    
    /*
        // Check if Actual has any bits that aren't set in Allowed
        AST.Modifiers.EFlags eDiff = eActual.Flags & ~eAllowed.Flags;
        
        // If no difference, then no error
        if (eDiff == Modifiers.EFlags.None)
            return;

        // We do have an error, so print out all flags                               
        AST.Modifiers modDiff = new Modifiers(eDiff);
        
        string st = modDiff.ToString();
        
        ThrowError(
            Code.cIllegalModifiers,
            location,
            "Modifiers '" + st + "' are not allowed on a '" + stTargetHint + "'"
        );
    */        
            
    }
     
    
    // Expected a statement expression
    //protected void ThrowError_ExpectedStatementExp(FileRange location)
    ParserErrorException E_ExpectedStatementExp(FileRange location)
    {   
        return new ParserErrorException(
            Code.cExpectedStatementExp,
            location,
            "Expected a statement expression"
        );
    }
    
    //protected void ThrowError_BadForLoopInit(FileRange location)
    ParserErrorException E_BadForLoopInit(FileRange location)
    {
        return new ParserErrorException(
            Code.cBadForInitializer,
            location,
            "The initializer in a for-loop must be either an expression-statement or a variable declaration");
    }
    
    // The given modifier appears multiple times. Modifiers can only appear once.
    /*
    protected void ThrowError_DuplicateModifier(FileRange location, AST.Modifiers.EFlags eFlag)
    {
        ThrowError(
            Code.cDuplicateModifier,
            location,
            "Duplicate '" + eFlag.ToString() + "' modifier.");
    }
    */
    
    //protected void ThrowError_NoBaseChainForStructs(FileRange location)
    ParserErrorException E_NoBaseChainForStructs(FileRange location)
    {
        return new ParserErrorException(
            Code.cNoBaseChainForStructs,
            location,
            "Constructors in Struct declarations can't chain to the base class");
    
    }
    
    //protected void ThrowError_NoCtorOnInterface(FileRange location)
    ParserErrorException E_NoCtorOnInterface(FileRange location)
    {
        return new ParserErrorException(
            Code.cNoCtorOnInterface,
            location,
            "Interfaces can't define constructors"
        );
    }
    
    //protected void ThrowError_NoDefaultCtorForStructs(FileRange location)
    ParserErrorException E_NoDefaultCtorForStructs(FileRange location)
    {
        return new ParserErrorException(
            Code.cNoDefaultCtorForStructs,
            location,
            "Structs can't have default constructors"
        );
    }
    
    ParserErrorException E_BadModsOnOps(FileRange location)
    {
        return new ParserErrorException(
            Code.cBadModsOnOps,
            location,
            "Overloaded operators must only have 'public' and 'static' modifiers"
        );
    }

⌨️ 快捷键说明

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