//class-dec ::= 'class' <class-name> '{' <class-var-dec>* <sub-dec>* '}' private void ParseClass() { Match(new Token(TokenType.Keyword, "class")); Token className = NextToken(); if (className == null) { Expected("class name"); } if (className.Type != TokenType.Ident) { Expected("identifier"); } _currentClassName = className.Value; _codeGenerator.BeginClass(className.Value); Match(new Token(TokenType.Symbol, "{")); ParseClassVarDecls(); ParseSubDecls(); Match(new Token(TokenType.Symbol, "}")); _codeGenerator.EndClass(); _currentClassName = String.Empty; _classSymTable.Clear(); }
private void ParseSubDecl() { Contract.Requires(IsNextTokenSubDecl()); Token subKind = NextToken(); Token returnType = NextToken(); Token subName = NextToken(); if (subKind.Type != TokenType.Keyword || !new[] { "constructor", "method", "function" }.Contains(subKind.Value)) { ThrowCompilationException("Expected: 'constructor', 'method', or 'function', but got: " + subKind.Value); } if (returnType.Type != TokenType.Keyword && returnType.Type != TokenType.Ident) { ThrowCompilationException("Invalid return type '" + returnType.Value + "'"); } if (subName.Type != TokenType.Ident) { ThrowCompilationException("Invalid subroutine name '" + subName.Value + "'"); } _currentSub = new Subroutine( (SubroutineKind)Enum.Parse(typeof(SubroutineKind), subKind.Value, ignoreCase: true), _currentClassName, subName.Value, returnType.Value); if (_currentSub.Kind == SubroutineKind.Constructor && _currentSub.ReturnType != _currentClassName) { ThrowCompilationException("Constructor must return '" + _currentClassName + "'"); } Match(new Token(TokenType.Symbol, "(")); ParseFormalParamList(); Match(new Token(TokenType.Symbol, ")")); //NOTE: We notify the code generator of the new subroutine only //after we have its local variable declarations. ParseSubBody(); _currentSub = null; _methodSymTable.Clear(); }