/// <summary> /// variable-declaration-part :: [ "var" variable-declaration ';' { variable-declaration ';' } ] . /// variable-declaration :: identifier-list ':' type-denoter . /// identifier-list :: identifier { ',' identifier } . /// type-denoter :: "integer" | "real" | "char" | "boolean" | "string" . /// </summary> /// <param name="programBlock">A program block containing this variables declaration list.</param> private void ParseVariableDeclarationPart(IProgramBlock programBlock) { if (Tokenizer.CurrentToken.TokenCode != TokenCode.TOK_KEY_VAR) { return; } // Eat "var". Tokenizer.NextToken(); while (true) { ParseVariableDeclaration(programBlock); // Get the token behind the last variable-declaration. var t = Tokenizer.CurrentToken; // ';' ? if (t.TokenCode != TokenCode.TOK_SEP) { throw new CompilerException(Tokenizer.CurrentLine, Tokenizer.CurrentLinePosition, "The end of variable declaration list (';') expected."); } // Eat ';'. t = Tokenizer.NextToken(); if (t.TokenCode != TokenCode.TOK_IDENT) { break; } } }
/// <summary> /// Constructor. /// </summary> /// <param name="parentBlock">The parent program block of this command.</param> public EmptyCommand(IProgramBlock parentBlock) { if (parentBlock == null) { throw new ArgumentNullException(nameof(parentBlock)); } Parent = parentBlock; }
/// <summary> /// compound-statement :: "begin" statement-sequence "end" . /// </summary> /// <param name="currentBlock">The currently parsed program block.</param> private void ParseCompoundStatement(IProgramBlock currentBlock) { // "BEGIN". ExpectAndEat(TokenCode.TOK_KEY_BEGIN, "The 'BEGIN' key word expected."); ParseStatementSequence(currentBlock); // "END". ExpectAndEat(TokenCode.TOK_KEY_END, "The 'END' key word expected."); }
/// <summary> /// Constructor. /// </summary> /// <param name="parentBlock">The parent program block of this command.</param> public WritelnCommand(IProgramBlock parentBlock, string parameter = null) { if (parentBlock == null) { throw new ArgumentNullException(nameof(parentBlock)); } Parent = parentBlock; Parameter = parameter; }
/// <summary> /// --block :: variable-declaration-part "begin" [ command { ';' command } ] "end" . /// /// block :: variable-declaration-part statement-part . /// variable-declaration-part :: [ "var" variable-declaration ';' { variable-declaration ';' } ] . /// statement-part :: compound-statement . /// compound-statement :: "begin" statement-sequence "end" . /// statement-sequence :: statement { ';' statement } . /// </summary> /// <param name="parentBlock">A parent program block.</param> /// <returns>An ICompiledProgramPart instance representing this compiled program part.</returns> private ICompiledProgramPart ParseBlock(IProgramBlock parentBlock) { var block = (parentBlock == null) ? (IProgramBlock) new ProgramBlock(parentBlock) : (IProgramBlock) new Block(parentBlock); ParseVariableDeclarationPart(block); ParseStatementPart(block); return(block); }
/// <summary> /// expression :: string . /// </summary> /// <param name="parentBlock"></param> /// <returns></returns> private ICompiledProgramPart ParseExpression(IProgramBlock parentBlock) { if (Tokenizer.CurrentToken.TokenCode == TokenCode.TOK_STR) { var s = Tokenizer.CurrentToken.StringValue; Eat(); return(new Expression(parentBlock, s)); } throw new CompilerException(Tokenizer.CurrentLine, Tokenizer.CurrentLinePosition, "An expression value expected."); }
/// <summary> /// statement :: [ label ':' ] ( simple-statement | structured-statement ) . /// simple-statement :: empty-statement | assignment-statement | procedure-statement | goto-statement . /// empty-statement :: . /// assignment-statement :: ( variable-access | function-identifier ) ":=" expression . /// procedure-statement :: procedure-identifier ( [ actual-parameter-list ] | read-parameter-list | readln-parameter-list | write-parameter-list | writeln-parameter-list ) . /// goto-statement :: "goto" label . /// structured-statement :: compound-statement | conditional-statement | repetitive-statement | with-statement . /// </summary> /// <param name="parentBlock">A parent program block.</param> /// <returns>An ICompiledProgramPart instance representing this compiled program part.</returns> private ICompiledProgramPart ParseStatement(IProgramBlock parentBlock) { var t = Tokenizer.CurrentToken; if (t.TokenCode == TokenCode.TOK_IDENT) { // TODO: Procedure or assignment or function? return(ParseProcedureStatement(parentBlock)); } else if (t.TokenCode == TokenCode.TOK_SEP || t.TokenCode == TokenCode.TOK_KEY_END) { return(new EmptyCommand(parentBlock)); } throw new CompilerException(Tokenizer.CurrentLine, Tokenizer.CurrentLinePosition, $"Unexpected token: {t}"); }
/// <summary> /// actual-parameter-list :: '(' actual-parameter { ',' actual-parameter } `)' . /// actual-parameter :: expression | variable-access | procedure-identifier | function-identifier . /// writeln-parameter-list :: '(' ( file-variable | write-parameter ) { ',' write-parameter } ')' . /// write-parameter :: expression [ ':' expression [ ':' expression ] ] . /// expression :: string . /// </summary> /// <param name="parentBlock">A parent program block.</param> /// <returns>An ICompiledProgramPart instance representing this compiled program part.</returns> private ICompiledProgramPart ParseWritelnParameterList(IProgramBlock parentBlock) { // Eat "("; var t = Tokenizer.NextToken(); if (t.TokenCode == TokenCode.TOK_STR) { var expression = (Expression)ParseExpression(parentBlock); // ')'. ExpectAndEat(TokenCode.TOK_RBRA, "The end of procedure parameters ')' expected."); return(new WritelnCommand(parentBlock, expression.SValue)); } throw new CompilerException(Tokenizer.CurrentLine, Tokenizer.CurrentLinePosition, "A procedure parameter expected."); }
/// <summary> /// procedure-statement :: procedure-identifier [ ( actual-parameter-list | read-parameter-list | readln-parameter-list | write-parameter-list | writeln-parameter-list ) ] . /// </summary> /// <param name="parentBlock"></param> /// <returns></returns> private ICompiledProgramPart ParseProcedureStatement(IProgramBlock parentBlock) { var procedureIdentifier = Tokenizer.CurrentToken.StringValue.ToUpperInvariant(); if (procedureIdentifier == "WRITELN") { // Eat "writeln". var t = Tokenizer.NextToken(); if (t.TokenCode == TokenCode.TOK_LBRA) { return(ParseWritelnParameterList(parentBlock)); } return(new WritelnCommand(parentBlock)); } throw new CompilerException(Tokenizer.CurrentLine, Tokenizer.CurrentLinePosition, $"Undefined identifier: {procedureIdentifier}"); }
/// <summary> /// statement-sequence :: statement { ';' statement } . /// </summary> /// <param name="currentBlock">The currently parsed program block.</param> private void ParseStatementSequence(IProgramBlock currentBlock) { var t = Tokenizer.CurrentToken; while (t.TokenCode != TokenCode.TOK_EOF) { currentBlock.AddCompiledProgramPart(ParseStatement(currentBlock)); t = Tokenizer.CurrentToken; if (t.TokenCode == TokenCode.TOK_KEY_END) { break; } if (t.TokenCode == TokenCode.TOK_SEP) { t = Tokenizer.NextToken(); continue; } throw new CompilerException(Tokenizer.CurrentLine, Tokenizer.CurrentLinePosition, "The ';' command separator expected."); } }
/// <summary> /// statement-part :: compound-statement . /// </summary> /// <param name="parentBlock"></param> /// <returns></returns> private void ParseStatementPart(IProgramBlock parentBlock) { ParseCompoundStatement(parentBlock); }
/// <summary> /// variable-declaration :: identifier-list ':' type-denoter . /// identifier-list :: identifier { ',' identifier } . /// type-denoter :: "integer" | "real" | "char" | "boolean" | "string" . /// </summary> /// <param name="programBlock"></param> /// <param name="currentToken"></param> private void ParseVariableDeclaration(IProgramBlock programBlock) { var t = Tokenizer.CurrentToken; if (t.TokenCode != TokenCode.TOK_IDENT) { throw new CompilerException(Tokenizer.CurrentLine, Tokenizer.CurrentLinePosition, "An identifier in the variable declaration list expected."); } var variablesList = new List <string>(); while (t.TokenCode == TokenCode.TOK_IDENT) { variablesList.Add(t.StringValue); // Eat the identifier. t = Tokenizer.NextToken(); // ','. if (t.TokenCode == TokenCode.TOK_LIST_SEP) { // Eat the ','. t = Tokenizer.NextToken(); if (t.TokenCode == TokenCode.TOK_IDENT) { continue; } throw new CompilerException(Tokenizer.CurrentLine, Tokenizer.CurrentLinePosition, "An identifier in the variable declaration list expected."); } // At the end of the variables list? break; } // ':'? if (t.TokenCode != TokenCode.TOK_DDOT) { throw new CompilerException(Tokenizer.CurrentLine, Tokenizer.CurrentLinePosition, "A variable type specification part expected."); } // Eat ':'. t = Tokenizer.NextToken(); // A type identifier. if (t.TokenCode != TokenCode.TOK_IDENT) { throw new CompilerException(Tokenizer.CurrentLine, Tokenizer.CurrentLinePosition, "A type denoter in variable declaration expected."); } var typeName = t.StringValue; // Eat identifier. Tokenizer.NextToken(); // Declare all found variables. foreach (var variableName in variablesList) { programBlock.AddVariableDeclaration(variableName, typeName); } }
public ProgramBlock(IProgramBlock parentBlock) : base(parentBlock) { }
public Expression(IProgramBlock parentBlock, string sValue) { ParentBlock = parentBlock; SValue = sValue; }
protected AProgramBlockBase(IProgramBlock parentBlock) { Parent = parentBlock; VariableDeclarations = new Dictionary <string, VariableDeclaration>(); Children = new List <ICompiledProgramPart>(); }