/// <summary> /// Parse a box /// </summary> public SyntaxBox ParseBox() { SyntaxBox box = ParseBoxPrototype(); // Skip box if we don't find 'is' after the prototype if (mTokenName != "is") { Reject("Expecting 'is' after box prototype", REJECT_BOX); return(box); } Accept("is"); box.Statements = ParseStatements(box, true); // Parse end of box statement if (mTokenName == "end") { mToken.InfoString = box.NameDecl.ToString(); Connect(box.NameDecl.TypeName, mToken); Accept(); } else { Reject("Expecting 'end' - end of box body", REJECT_BOX); } return(box); }
/// <summary> /// Recompile or display hover message when necessary /// </summary> private void timer1_Tick(object sender, EventArgs e) { // Recompile 250 milliseconds after the user stops typing if (mLastEditorChangedTime != new DateTime() && (DateTime.Now - mLastEditorChangedTime).TotalMilliseconds > 250) { try { // Reset the lexer, re-parse, and compile mLastEditorChangedTime = new DateTime(); Parser parser = new Parser(editor1.Lexer); DateTime t1 = DateTime.Now; SyntaxBox program = parser.Parse(); DateTime t2 = DateTime.Now; CodeBox code = new CodeBox(null, program); DateTime t3 = DateTime.Now; editor1.Invalidate(); // Debug times TimeSpan parseTime = t2 - t1; TimeSpan genTime = t3 - t2; } catch (Exception ex) { MessageBox.Show(this, "Error compiling: " + ex.Message, App.Name); } } // Find out if all simulation form windows have closed for (int i = 0; i < mSimulationForms.Count; i++) { if (mSimulationForms[i].IsDisposed) { mSimulationForms.RemoveAt(i); } } // Make the editor read-only if there is a simulation form open editor1.ReadOnly = mSimulationForms.Count != 0; // Display the hover message (after no mouse movement for 150 milliseconds) if (mHoverToken != null && mHoverToken.Type != eTokenType.Comment && mHoverToken.InfoString != "" && (DateTime.Now - mLastMouseMoveTime).TotalMilliseconds > 150 && !mHoverMessageForm.Visible) { // Set form size, location, and text mHoverMessageForm.Message.Text = mHoverToken.InfoString; Size s = mHoverMessageForm.Message.Size; mHoverMessageForm.ClientSize = new Size(s.Width + 8, s.Height + 8); Point p = editor1.PointToScreen(editor1.LocationToken(mHoverToken.Location)); p.Y -= s.Height + 32; mHoverMessageForm.Location = p; // Display the form mHoverMessageForm.Show(this); this.Focus(); } }
/// <summary> /// Parse multiple statements until 'box', 'end', 'else', or 'elif' /// is found. Returns the statements that are parsed. /// Adds declarations to the box locals. Never returns NULL. /// </summary> public SyntaxExpr ParseStatements(SyntaxBox box, bool topLevel) { // Create an "{" expression, which (for now means "statements") SyntaxExpr statements = new SyntaxExpr(mInternalTokenStatement); // While not end of file and not end of box and not new box while (mTokenName != "" && mTokenName != "box" && mTokenName != "end" && mTokenName != "else" && mTokenName != "elif") { // Skip blank statements while (mTokenName == ";") { Accept(); } // Parse the statement SyntaxExpr statement = ParseStatement(box, topLevel); if (statement != null) { statements.AddParam(statement); } while (mTokenName == ";") { Accept(); } } return(statements); }
/// <summary> /// Parse an if statement (expects 'if' at the input) /// </summary> SyntaxExpr ParseIfStatement(SyntaxBox box) { // Parse "if" token, condition, and statements Token ifToken = mToken; Accept("if"); SyntaxExpr ifExpr = new SyntaxExpr(ifToken); ifExpr.AddParam(ParseIfCond()); ifExpr.AddParam(ParseStatements(box, false)); // Parse "elif" statements SyntaxExpr elseExpr = ifExpr; while (mTokenName == "elif") { // Parse "elif" token, condition, and statements // NOTE: "elif" token is converted to "if" Connect(ifToken, mToken); Accept("elif"); SyntaxExpr newIf = new SyntaxExpr(ifToken); newIf.AddParam(ParseIfCond()); newIf.AddParam(ParseStatements(box, false)); // Convert the new "elif" to "else if" elseExpr.AddParam(newIf); elseExpr = newIf; } // Parse the "else" clause (if it exists) if (mTokenName == "else") { Connect(ifToken, mToken); Accept("else"); elseExpr.AddParam(ParseStatements(box, false)); } // Parse end of box statement if (mTokenName == "end") { mToken.InfoString = "end if"; Connect(ifToken, mToken); Accept(); } else { Reject("Expecting 'end' - end of if statement body", REJECT_BOX); } // Parse "else" part return(ifExpr); }
/// <summary> /// Show simulation form /// </summary> private void menuSimulateNew_Click(object sender, EventArgs e) { // Compile everything Parser parser = new Parser(editor1.Lexer); SyntaxBox program = parser.Parse(); CodeBox code = new CodeBox(null, program); editor1.Invalidate(); // Get the code boxes List <CodeBox> boxes = new List <CodeBox>(); foreach (var box in code.Boxes) { if (box.Decl.TypeName == "box" && box.CodeBoxValue != null) { boxes.Add(box.CodeBoxValue); } } if (boxes.Count == 0) { MessageBox.Show(this, "No boxes were defined", App.Name); return; } // Show the simulation form FormSetupSimulation setupForm = new FormSetupSimulation(); setupForm.Boxes = boxes; setupForm.ShowDialog(this); // Show a form if requested by setup form if (setupForm.FormResult != null) { setupForm.FormResult.Show(); } // Go to read-only mode if running a simulation if (setupForm.FormResult as FormSimulate != null) { mSimulationForms.Add(setupForm.FormResult as FormSimulate); editor1.ReadOnly = true; } }
/// <summary> /// Parse an entire file. /// </summary> public SyntaxBox Parse() { // Top level scope SyntaxBox program = new SyntaxBox(); program.NameDecl.TypeName = new Token("SCOPE:0", 0, 0); program.NameDecl.VariableName = new Token("SCOPE:0", 0, 0); while (mTokenName != "") { // Parse a box if (mTokenName == "box") { mParseError = false; SyntaxBox box = ParseBox(); box.Parent = program; program.Boxes.Add(box); box.Error = mParseError; } else if (mTokenName == "const") { program.Constants.Add(ParseConstStatement()); // Ensure we have a valid statement if (mTokenName != ";") { Reject("Expecting end of statement separator ';'", REJECT_LINE); } while (mTokenName == ";") { Accept(); } } else { Reject("Invalid token \'" + mTokenName + "\' was found when expecting the keyword 'box' or 'const'", REJECT_BOX); } } return(program); }
/// <summary> /// Parse a box prototype, returns new box with parameters filled in. /// </summary> public SyntaxBox ParseBoxPrototype() { if (mTokenName != "box") { throw new Exception("ParseBoxPrototype: expecting 'box'"); } // Read box declaration name SyntaxBox box = new SyntaxBox(); box.NameDecl = ParseBoxDeclarationName(REJECT_BOX_PROTOTYPE); if (mTokenName == "(") { box.Params = ParseBoxDeclarationParameters(); } else { Reject("Expecting \'(\' or \'[\' in box declaration", REJECT_BOX_PROTOTYPE); } return(box); }
/// <summary> /// Parse a single statement, which could be an expression. /// Adds declaratins to the box locals. /// NOTE: This can return NULL if there are no statements. /// </summary> public SyntaxExpr ParseStatement(SyntaxBox box, bool topLevel) { while (mTokenName == "else" || mTokenName == "elif") { Reject("This '" + mTokenName + "' is not inside an 'if' statement"); Accept(); } // Check statement keywords first bool needsSemicolon = true; SyntaxExpr result = null; if (mTokenName == "bit") { // Parse bit statement (optionally followed by assignment) if (!topLevel) { Reject("'bit' declarations are only allowed at the top level"); } result = ParseBitStatement(REJECT_LINE); } else if (mTokenName == "const") { // Parse const declaration if (!topLevel) { Reject("'const' declarations are only allowed at the top level"); } result = ParseConstStatement(); } else if (mTokenName == "if") { // Parse if statement needsSemicolon = false; result = ParseIfStatement(box); } else { // Parse an expression result = ParseExpr(); // Assignment statement? if (mTokenName == "=") { // Generate an assignment statement result = new SyntaxExpr(Accept(), result, ParseExpr()); } } // Ensure we have a valid statement if (needsSemicolon && mTokenName != ";") { Reject("Expecting end of statement separator ';'", REJECT_LINE); } if (mTokenName == ";") { Accept(); } return(result); }