📄 parser.cs
字号:
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 + -