diff --git a/pseudocodeIde/PseudocodeIDEForm.Designer.cs b/pseudocodeIde/PseudocodeIDEForm.Designer.cs index cb5c1c1..b9205e4 100644 --- a/pseudocodeIde/PseudocodeIDEForm.Designer.cs +++ b/pseudocodeIde/PseudocodeIDEForm.Designer.cs @@ -61,6 +61,7 @@ private void InitializeComponent() // // menuStrip // + this.menuStrip.GripMargin = new System.Windows.Forms.Padding(2, 2, 0, 2); this.menuStrip.ImageScalingSize = new System.Drawing.Size(24, 24); this.menuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.fileMenuItem, @@ -81,7 +82,7 @@ private void InitializeComponent() this.openMenuItem, this.saveMenuItem}); this.fileMenuItem.Name = "fileMenuItem"; - this.fileMenuItem.Size = new System.Drawing.Size(69, 29); + this.fileMenuItem.Size = new System.Drawing.Size(69, 32); this.fileMenuItem.Text = "Datei"; // // newMenuItem @@ -120,7 +121,7 @@ private void InitializeComponent() this.toolStripSeparator4, this.goToMenuItem}); this.editMenuItem.Name = "editMenuItem"; - this.editMenuItem.Size = new System.Drawing.Size(111, 29); + this.editMenuItem.Size = new System.Drawing.Size(111, 32); this.editMenuItem.Text = "Bearbeiten"; // // undoToolStripMenuItem @@ -180,7 +181,7 @@ private void InitializeComponent() this.viewMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.wordWrapMenuItem}); this.viewMenuItem.Name = "viewMenuItem"; - this.viewMenuItem.Size = new System.Drawing.Size(86, 29); + this.viewMenuItem.Size = new System.Drawing.Size(86, 32); this.viewMenuItem.Text = "Ansicht"; // // wordWrapMenuItem @@ -199,7 +200,7 @@ private void InitializeComponent() this.toolStripSeparator2, this.singleEqualIsCompareOperatorMenuItem}); this.runMenuItem.Name = "runMenuItem"; - this.runMenuItem.Size = new System.Drawing.Size(109, 29); + this.runMenuItem.Size = new System.Drawing.Size(109, 32); this.runMenuItem.Text = "Ausführen"; // // runProgramMenuItem @@ -242,7 +243,7 @@ private void InitializeComponent() this.updateMenuItem, this.updateBetaMenuItem}); this.helpMenuItem.Name = "helpMenuItem"; - this.helpMenuItem.Size = new System.Drawing.Size(64, 29); + this.helpMenuItem.Size = new System.Drawing.Size(64, 32); this.helpMenuItem.Text = "Hilfe"; // // showHelpMenuItem diff --git a/pseudocodeIde/PseudocodeIDEForm.cs b/pseudocodeIde/PseudocodeIDEForm.cs index 975086b..9a8eff2 100644 --- a/pseudocodeIde/PseudocodeIDEForm.cs +++ b/pseudocodeIde/PseudocodeIDEForm.cs @@ -24,6 +24,7 @@ using System.Drawing; using System.IO; using System.Linq; +using System.Net; using System.Reflection; using System.Text.RegularExpressions; using System.Windows.Forms; @@ -37,6 +38,17 @@ public partial class PseudocodeIDEForm : Form /// private const int MAX_UNDO_SIZE = 250; + // Indicators 0-7 could be in use by a lexer so we'll use indicator 8 + /// + /// Indicator ID for highlighting words. + /// + public const int WORD_HIGHLIGHT_INDICATOR_ID = 8; + + /// + /// Indicator ID for selecting the next word via tab. + /// + public const int TAB_SELECTION_INDICATOR_ID = 9; + /// /// do not update the undo stack when the last char is a letter from A-Z (case ignored), a number from 0-9 or a underscore /// @@ -100,9 +112,15 @@ public string Code /// private int _maxLineNumberCharLength; + /// + /// Contains the instance of this form + /// + public static PseudocodeIDEForm Instance; public PseudocodeIDEForm() { + Instance = this; + InitializeComponent(); _outputForm = new OutputForm(this); _findReplace = new FindReplace(codeTextBox); @@ -224,9 +242,12 @@ private void PseudocodeIDE_FormClosing(object sender, FormClosingEventArgs e) } // --------------------------------------------- - // CODE TEXTBOX EVENT LISTENERS + // CODE TEXTBOX (Scintilla) // --------------------------------------------- + /// + /// Updates the undo stack, when user updated the code + /// private void UserUpdatedText() { // only update undo stack if next event not ignored @@ -240,6 +261,36 @@ private void UserUpdatedText() } } + /// + /// User changed selection + /// + private void UserChangedSelection() + { + HighlightWord(codeTextBox.SelectedText); + RemovePreviousTabSelectionIndicators(); + + TryHandleSelectionChange(); + } + + /// + /// Forcefully updates the undoStack, when the cursor moved more than 1 since last check or the user selected something + /// + private void TryHandleSelectionChange() + { + // ignore when we already undid something + if (_redoStack.Count != 0) + { + _lastCursorPosition = codeTextBox.SelectionStart; + return; + } + + if (codeTextBox.SelectionEnd - codeTextBox.SelectionStart != 0 || Math.Abs(_lastCursorPosition - codeTextBox.SelectionStart) > 1) + { + UpdateUndoStack(true); + } + _lastCursorPosition = codeTextBox.SelectionStart; + } + private void CodeTextBox_UpdateUI(object sender, UpdateUIEventArgs e) { switch (e.Change) @@ -257,6 +308,12 @@ private void CodeTextBox_TextChanged(object sender, EventArgs e) { // when the code is modified, the code is no longer saved in the file SetFileNotSaved(); + + // only update undo stack if next event not ignored + if (!IgnoreTextChange) + { + TryHandleSelectionChange(); + } // Did the number of characters in the line number display change? int maxLineNumberCharLength = codeTextBox.Lines.Count.ToString().Length; @@ -274,6 +331,11 @@ private void CodeTextBox_TextChanged(object sender, EventArgs e) private void CodeTextBox_KeyDown(object sender, KeyEventArgs e) { + if (e.KeyCode == Keys.Tab && e.Modifiers == Keys.None) + { + e.SuppressKeyPress = TrySelectNextTabIndicator(); + } + // hack to allow enter to autocomplete even if down wasnt pressed before if ((e.KeyCode == Keys.Enter || e.KeyCode == Keys.Tab) && e.Modifiers == Keys.None && autoCompleteMenu.SelectedItemIndex < 0) { @@ -296,11 +358,13 @@ private void CodeTextBox_KeyDown(object sender, KeyEventArgs e) e.SuppressKeyPress = false; return; } + // find replace: find previous else if (e.Shift && e.KeyCode == Keys.F3) { _findReplace.Window.FindPrevious(); e.SuppressKeyPress = true; } + // find replace: find next else if (e.KeyCode == Keys.F3) { _findReplace.Window.FindNext(); @@ -308,6 +372,116 @@ private void CodeTextBox_KeyDown(object sender, KeyEventArgs e) } } + /// + /// Add indicators to scintilla, where the variables are, so that the user can tab through them + /// + /// + /// + public void AddTabSelectionIndicators(List<(int selectionStart, int selectionEnd)> tabSelections) + { + if (tabSelections.Count >= 1) + { + codeTextBox.SelectionStart = tabSelections.First().selectionStart; + codeTextBox.SelectionEnd = tabSelections.First().selectionEnd; + tabSelections.RemoveAt(0); + } + + // remove all uses of our indicator + codeTextBox.IndicatorCurrent = TAB_SELECTION_INDICATOR_ID; + codeTextBox.IndicatorClearRange(0, codeTextBox.TextLength); + + if (tabSelections.Count == 0) + { + return; + } + + // update indicator appearance + codeTextBox.Indicators[TAB_SELECTION_INDICATOR_ID].Style = IndicatorStyle.StraightBox; + codeTextBox.Indicators[TAB_SELECTION_INDICATOR_ID].Under = true; + codeTextBox.Indicators[TAB_SELECTION_INDICATOR_ID].ForeColor = Color.LightBlue; + codeTextBox.Indicators[TAB_SELECTION_INDICATOR_ID].OutlineAlpha = 255; + codeTextBox.Indicators[TAB_SELECTION_INDICATOR_ID].Alpha = 100; + + foreach ((int selectionStart, int selectionEnd) in tabSelections) + { + codeTextBox.IndicatorFillRange(selectionStart, selectionEnd - selectionStart); + } + + UpdateUndoStack(true); + } + + /// + /// Try to select the next tab indicator on tab press + /// + /// true if the next indicator was selected + private bool TrySelectNextTabIndicator() + { + (int, int)? firstSelection = GetFirstTabSelectionTuple(); + if (firstSelection != null) + { + (int selectionStart, int selectionEnd) = firstSelection.Value; + + codeTextBox.IndicatorCurrent = TAB_SELECTION_INDICATOR_ID; + codeTextBox.IndicatorClearRange(selectionStart, selectionEnd - selectionStart); + codeTextBox.SelectionStart = selectionStart; + codeTextBox.SelectionEnd = selectionEnd; + return true; + } + return false; + } + + /// + /// Get the selection start and end of the first tab selection indicator + /// + /// null if there is no tab selection indicator + private (int selectionStart, int selectionEnd)? GetFirstTabSelectionTuple() + { + int textLength = codeTextBox.TextLength; + Indicator indicator = codeTextBox.Indicators[TAB_SELECTION_INDICATOR_ID]; + int bitmapFlag = (1 << indicator.Index); + + int endPos = 0; + do + { + int startPos = indicator.Start(endPos); + endPos = indicator.End(startPos); + + // Is this range filled with our indicator (TAB_SELECTION_INDICATOR_ID)? + uint bitmap = codeTextBox.IndicatorAllOnFor(startPos); + bool filled = ((bitmapFlag & bitmap) == bitmapFlag); + if (filled) + { + return (startPos, endPos); + } + } while (endPos != 0 && endPos < textLength); + + return null; + } + + /// + /// Removes all tab completion that are present before the selection end + /// + private void RemovePreviousTabSelectionIndicators() + { + (int, int)? firstSelection = GetFirstTabSelectionTuple(); + while (firstSelection != null) + { + (int selectionStart, int selectionEnd) = firstSelection.Value; + + if (selectionEnd <= codeTextBox.SelectionEnd) + { + codeTextBox.IndicatorCurrent = TAB_SELECTION_INDICATOR_ID; + codeTextBox.IndicatorClearRange(selectionStart, selectionEnd - selectionStart); + } + else + { + break; + } + + firstSelection = GetFirstTabSelectionTuple(); + } + } + private void CodeTextBox_KeyPress(object sender, KeyPressEventArgs e) { // keep tab indentation from previous line on new line @@ -330,27 +504,11 @@ private void CodeTextBox_CharAdded(object sender, CharAddedEventArgs e) { int caretPos = codeTextBox.CurrentPosition; bool docStart = caretPos == 1; - bool docEnd = caretPos == codeTextBox.Text.Length; - - int charPrev = docStart ? codeTextBox.GetCharAt(caretPos) : codeTextBox.GetCharAt(caretPos - 2); - int charNext = codeTextBox.GetCharAt(caretPos); - - bool isCharPrevBlank = charPrev == ' ' || charPrev == '\t' || - charPrev == '\n' || charPrev == '\r'; - bool isCharNextBlank = charNext == ' ' || charNext == '\t' || - charNext == '\n' || charNext == '\r' || - docEnd; + char charPrev = (char)(docStart ? codeTextBox.GetCharAt(caretPos) : codeTextBox.GetCharAt(caretPos - 2)); + char charNext = (char)codeTextBox.GetCharAt(caretPos); - bool isEnclosed = (charPrev == '(' && charNext == ')') || - (charPrev == '{' && charNext == '}') || - (charPrev == '[' && charNext == ']'); - - bool isSpaceEnclosed = (charPrev == '(' && isCharNextBlank) || (isCharPrevBlank && charNext == ')') || - (charPrev == '{' && isCharNextBlank) || (isCharPrevBlank && charNext == '}') || - (charPrev == '[' && isCharNextBlank) || (isCharPrevBlank && charNext == ']'); - - bool isCharOrString = docStart || (isCharPrevBlank && isCharNextBlank) || isEnclosed || isSpaceEnclosed; + bool addClosingQuotes = docStart || !Scanner.IsAlphaNumeric(charNext) && !Scanner.IsAlphaNumeric(charPrev); switch (e.Char) { @@ -395,7 +553,7 @@ private void CodeTextBox_CharAdded(object sender, CharAddedEventArgs e) return; } - if (isCharOrString) + if (addClosingQuotes) { codeTextBox.InsertText(caretPos, "\""); } @@ -408,7 +566,7 @@ private void CodeTextBox_CharAdded(object sender, CharAddedEventArgs e) return; } - if (isCharOrString) + if (addClosingQuotes) { codeTextBox.InsertText(caretPos, "'"); } @@ -416,34 +574,11 @@ private void CodeTextBox_CharAdded(object sender, CharAddedEventArgs e) } } - private void UserChangedSelection() - { - // ignore when we already undid something - if (_redoStack.Count != 0) - { - _lastCursorPosition = codeTextBox.SelectionStart; - return; - } - - // update undo stack when user selected something or cursor moved by more then one since last time - if (codeTextBox.SelectionEnd - codeTextBox.SelectionStart != 0 || Math.Abs(_lastCursorPosition - codeTextBox.SelectionStart) > 1) - { - UpdateUndoStack(true); - } - _lastCursorPosition = codeTextBox.SelectionStart; - - HighlightWord(codeTextBox.SelectedText); - } - // adapted from https://github.com/desjarlais/Scintilla.NET/wiki/Find-and-Highlight-Words private void HighlightWord(string text) { - // Indicators 0-7 could be in use by a lexer - // so we'll use indicator 8 to highlight words. - const int NUM = 8; - // Remove all uses of our indicator - codeTextBox.IndicatorCurrent = NUM; + codeTextBox.IndicatorCurrent = WORD_HIGHLIGHT_INDICATOR_ID; codeTextBox.IndicatorClearRange(0, codeTextBox.TextLength); if (string.IsNullOrEmpty(text)) @@ -452,11 +587,11 @@ private void HighlightWord(string text) } // Update indicator appearance - codeTextBox.Indicators[NUM].Style = IndicatorStyle.StraightBox; - codeTextBox.Indicators[NUM].Under = true; - codeTextBox.Indicators[NUM].ForeColor = Color.Lime; - codeTextBox.Indicators[NUM].OutlineAlpha = 127; - codeTextBox.Indicators[NUM].Alpha = 100; + codeTextBox.Indicators[WORD_HIGHLIGHT_INDICATOR_ID].Style = IndicatorStyle.StraightBox; + codeTextBox.Indicators[WORD_HIGHLIGHT_INDICATOR_ID].Under = true; + codeTextBox.Indicators[WORD_HIGHLIGHT_INDICATOR_ID].ForeColor = Color.Lime; + codeTextBox.Indicators[WORD_HIGHLIGHT_INDICATOR_ID].OutlineAlpha = 100; + codeTextBox.Indicators[WORD_HIGHLIGHT_INDICATOR_ID].Alpha = 100; // Search the document codeTextBox.TargetStart = 0; @@ -734,14 +869,13 @@ private void UndoToolStripMenuItem_Click(object sender, EventArgs e) redoToolStripMenuItem.Enabled = true; } + int oldSelectionStart = codeTextBox.SelectionStart; // the undo stack always has at least one item in it if (_undoStack.Count <= 1) { // set the textbox text to the item without removing it from the stack IgnoreTextChange = true; - int oldSelectionStart = codeTextBox.SelectionStart; codeTextBox.Text = _undoStack.Peek(); - codeTextBox.SelectionStart = Math.Min(oldSelectionStart, codeTextBox.TextLength); // no more things to undo undoToolStripMenuItem.Enabled = false; @@ -749,7 +883,6 @@ private void UndoToolStripMenuItem_Click(object sender, EventArgs e) else { string currentText = codeTextBox.Text; - int oldSelectionStart = codeTextBox.SelectionStart; // set the textbox text to the first item that doesn't match the current text. also remove them from the undo stack do @@ -757,9 +890,8 @@ private void UndoToolStripMenuItem_Click(object sender, EventArgs e) IgnoreTextChange = true; codeTextBox.Text = _undoStack.Peek(); } while (_undoStack.Count > 1 && currentText.Equals(_undoStack.Pop())); - - codeTextBox.SelectionStart = Math.Min(oldSelectionStart, codeTextBox.TextLength); } + codeTextBox.SelectionStart = oldSelectionStart; } private void RedoToolStripMenuItem_Click(object sender, EventArgs e) diff --git a/pseudocodeIde/SetClipboardHelper.cs b/pseudocodeIde/SetClipboardHelper.cs index e5e6d33..44ec2ab 100644 --- a/pseudocodeIde/SetClipboardHelper.cs +++ b/pseudocodeIde/SetClipboardHelper.cs @@ -20,20 +20,20 @@ namespace pseudocode_ide public class SetClipboardHelper : StaHelper { - readonly string FORMAT; - readonly object DATA; + private readonly string _format; + private readonly object _data; public SetClipboardHelper(string format, object data) { - FORMAT = format; - DATA = data; + _format = format; + _data = data; } protected override void Work() { DataObject obj = new System.Windows.Forms.DataObject( - FORMAT, - DATA + _format, + _data ); Clipboard.SetDataObject(obj, true); @@ -42,7 +42,7 @@ protected override void Work() public abstract class StaHelper { - readonly ManualResetEvent COMPLETE = new ManualResetEvent(false); + readonly ManualResetEvent _complete = new ManualResetEvent(false); public void Go() { @@ -59,7 +59,7 @@ private void DoWork() { try { - COMPLETE.Reset(); + _complete.Reset(); Work(); } catch (Exception ex) @@ -78,13 +78,13 @@ private void DoWork() catch { // ex from first exception - Debug.WriteLine(ex); + MessageBox.Show(ex.ToString(), "Error"); } } } finally { - COMPLETE.Set(); + _complete.Set(); } } diff --git a/pseudocodeIde/interpreter/pseudocode/PseudocodeAutocompleteItem.cs b/pseudocodeIde/interpreter/pseudocode/PseudocodeAutocompleteItem.cs index 3c4e1c4..7fd04ae 100644 --- a/pseudocodeIde/interpreter/pseudocode/PseudocodeAutocompleteItem.cs +++ b/pseudocodeIde/interpreter/pseudocode/PseudocodeAutocompleteItem.cs @@ -12,6 +12,11 @@ using AutocompleteMenuNS; using pseudocodeIde; using ScintillaNET; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using static System.Net.Mime.MediaTypeNames; namespace pseudocode_ide.interpreter.pseudocode { @@ -43,8 +48,56 @@ public override string GetTextForReplace() string line = scintilla.Lines[scintilla.LineFromPosition(Parent.Fragment.Start)].Text; string indents = new string('\t', line.GetIndentationLevel()); + Text = Text.Replace("\n", $"\n{indents}"); - return Text.Replace("\n", $"\n{indents}"); + return Text; + } + + /// + /// After this item got selected (the text is already pasted in scintilla), put all the variable locations in a list + /// + /// + public override void OnSelected(SelectedEventArgs e) + { + Scintilla scintilla = (Scintilla)Parent.TargetControlWrapper.TargetControl; + List<(int selectionStart, int selectionEnd)> tabSelections = new List<(int selectionStart, int selectionEnd)>(); + + bool inSelection = false; + int textLengthWithoutMarkers = Text.Replace("\\^", " ").Replace("^", "").Length; + for (int i = Parent.Fragment.Start; ; i++) + { + recheck: + if (i >= Parent.Fragment.Start + textLengthWithoutMarkers) { + break; + } + + if (scintilla.Text[i] == '^') + { + if (i != 0 && scintilla.Text[i - 1] == '\\') + { + scintilla.Text = scintilla.Text.Remove(i - 1, 1); + goto recheck; + } + + scintilla.Text = scintilla.Text.Remove(i, 1); + + if (!inSelection) // && firstOccurrenceSelected + { + tabSelections.Add((selectionStart: i, selectionEnd: Parent.Fragment.Start + textLengthWithoutMarkers )); + inSelection = true; + } + else // inSelection && firstOccurrenceSelected + { + (int selectionStart, int selectionEnd) lastSelection = tabSelections.Last(); + lastSelection.selectionEnd = i; + tabSelections[tabSelections.Count - 1] = lastSelection; + + inSelection = false; + } + } + } + + PseudocodeIDEForm.Instance.AddTabSelectionIndicators(tabSelections); } } } diff --git a/pseudocodeIde/interpreter/pseudocode/PseudocodeKeywords.cs b/pseudocodeIde/interpreter/pseudocode/PseudocodeKeywords.cs index 2bd8faa..c7f4b83 100644 --- a/pseudocodeIde/interpreter/pseudocode/PseudocodeKeywords.cs +++ b/pseudocodeIde/interpreter/pseudocode/PseudocodeKeywords.cs @@ -29,42 +29,25 @@ static PseudocodeKeywords() // code block snippets KEYWORDS.Add(new PseudocodeType("WENN", IF, new List() { - new PseudocodeAutocompleteItem("WENN ^\n\t\nENDE WENN", "WENN Block"), - new PseudocodeAutocompleteItem("WENN ^\n\t\nSONST\n\t\nENDE WENN", "WENN-SONST Block") + new PseudocodeAutocompleteItem("WENN ^bedingung^\n\t^code^\nENDE WENN", "WENN Block"), + new PseudocodeAutocompleteItem("WENN ^bedingung^\n\t^code^\nSONST\n\t^code^\nENDE WENN", "WENN-SONST Block") })); - KEYWORDS.Add(new PseudocodeType("FALLS", SWITCH_PREFIX, "FALLS ^ GLEICH\n\tbedingung1:\n\t\t\n\tSONST:\n\t\t\nENDE FALLS")); - KEYWORDS.Add(new PseudocodeType("SOLANGE", WHILE, "SOLANGE ^\n\t\nENDE SOLANGE")); - KEYWORDS.Add(new PseudocodeType("WIEDERHOLE", DO, "WIEDERHOLE\n\t\nSOLANGE ^")); + KEYWORDS.Add(new PseudocodeType("FALLS", SWITCH_PREFIX, "FALLS ^variable^ GLEICH\n\t^bedingung1^:\n\t\t^code^\n\tSONST:\n\t\t^code^\nENDE FALLS")); + KEYWORDS.Add(new PseudocodeType("SOLANGE", WHILE, "SOLANGE ^bedingung^\n\t\nENDE SOLANGE")); + KEYWORDS.Add(new PseudocodeType("WIEDERHOLE", DO, "WIEDERHOLE\n\t\nSOLANGE ^bedingung^")); KEYWORDS.Add(new PseudocodeType("FÜR", FOR, new List() { - new PseudocodeAutocompleteItem("FÜR ^ BIS SCHRITT \n\t\nENDE FÜR", "FÜR-BIS Block"), - new PseudocodeAutocompleteItem("FÜR ^ IN \n\t\nENDE FÜR", "FÜR-IN Block") + new PseudocodeAutocompleteItem("FÜR ^variable^ BIS ^endwert^ SCHRITT ^erhöhung^\n\t^code^\nENDE FÜR", "FÜR-BIS Block"), + new PseudocodeAutocompleteItem("FÜR ^variable^ IN ^liste^\n\t^code^\nENDE FÜR", "FÜR-IN Block") })); - KEYWORDS.Add(new PseudocodeType("OPERATION", FUNCTION, "OPERATION ^()\n\t")); - KEYWORDS.Add(new PseudocodeType("Liste", TYPE_LIST, "Liste<^>")); + KEYWORDS.Add(new PseudocodeType("OPERATION", FUNCTION, "OPERATION ^name^()\n\t")); + KEYWORDS.Add(new PseudocodeType("Liste", TYPE_LIST, "Liste<^Typ^>")); // built-in methods - KEYWORDS.Add(new PseudocodeType("schreibe", IDENTIFIER, "schreibe(^)")); - KEYWORDS.Add(new PseudocodeType("warte", IDENTIFIER, "warte(^)")); - KEYWORDS.Add(new PseudocodeType("benutzereingabe", IDENTIFIER, "benutzereingabe<^>(\"\", \"\")")); + KEYWORDS.Add(new PseudocodeType("schreibe", IDENTIFIER, "schreibe(^wert^)")); + KEYWORDS.Add(new PseudocodeType("warte", IDENTIFIER, "warte(^millisekunden^)")); + KEYWORDS.Add(new PseudocodeType("benutzereingabe", IDENTIFIER, "benutzereingabe<^Rückgabetyp^>(^nachricht^, ^titel^)")); - // if/else - KEYWORDS.Add(new PseudocodeType("SONST", ELSE)); - KEYWORDS.Add(new PseudocodeType("ENDE WENN", END_IF)); - - - // switch/case - KEYWORDS.Add(new PseudocodeType("GLEICH", SWITCH_SUFFIX)); - KEYWORDS.Add(new PseudocodeType("ENDE FALLS", END_SWITCH)); - - // (do) while - KEYWORDS.Add(new PseudocodeType("ENDE SOLANGE", END_WHILE)); - - // for - KEYWORDS.Add(new PseudocodeType("BIS", FOR_TO)); - KEYWORDS.Add(new PseudocodeType("SCHRITT", FOR_STEP)); - KEYWORDS.Add(new PseudocodeType("IN", FOR_IN)); - KEYWORDS.Add(new PseudocodeType("ENDE FÜR", END_FOR)); // break KEYWORDS.Add(new PseudocodeType("ABBRUCH", BREAK)); @@ -83,19 +66,19 @@ static PseudocodeKeywords() KEYWORDS.Add(new PseudocodeType("ODER", OR)); // boolean types + KEYWORDS.Add(new PseudocodeType("bool", TYPE_BOOL)); KEYWORDS.Add(new PseudocodeType("Boolean", TYPE_BOOL)); KEYWORDS.Add(new PseudocodeType("boolean", TYPE_BOOL)); - KEYWORDS.Add(new PseudocodeType("bool", TYPE_BOOL)); // int types KEYWORDS.Add(new PseudocodeType("GZ", TYPE_INT)); - KEYWORDS.Add(new PseudocodeType("Integer", TYPE_INT)); KEYWORDS.Add(new PseudocodeType("int", TYPE_INT)); + KEYWORDS.Add(new PseudocodeType("Integer", TYPE_INT)); // double types KEYWORDS.Add(new PseudocodeType("FKZ", TYPE_DOUBLE)); - KEYWORDS.Add(new PseudocodeType("Real", TYPE_DOUBLE)); KEYWORDS.Add(new PseudocodeType("double", TYPE_DOUBLE)); + KEYWORDS.Add(new PseudocodeType("Real", TYPE_DOUBLE)); // char types KEYWORDS.Add(new PseudocodeType("Zeichen", TYPE_CHAR)); @@ -103,14 +86,31 @@ static PseudocodeKeywords() // string types KEYWORDS.Add(new PseudocodeType("Text", TYPE_STRING)); - KEYWORDS.Add(new PseudocodeType("String", TYPE_STRING)); KEYWORDS.Add(new PseudocodeType("string", TYPE_STRING)); + KEYWORDS.Add(new PseudocodeType("String", TYPE_STRING)); + + // null + KEYWORDS.Add(new PseudocodeType("NICHTS", NULL)); // new keyword KEYWORDS.Add(new PseudocodeType("NEU", NEW)); - // null - KEYWORDS.Add(new PseudocodeType("NICHTS", NULL)); + // if/else + KEYWORDS.Add(new PseudocodeType("SONST", ELSE)); + KEYWORDS.Add(new PseudocodeType("ENDE WENN", END_IF)); + + // switch/case + KEYWORDS.Add(new PseudocodeType("GLEICH", SWITCH_SUFFIX)); + KEYWORDS.Add(new PseudocodeType("ENDE FALLS", END_SWITCH)); + + // (do) while + KEYWORDS.Add(new PseudocodeType("ENDE SOLANGE", END_WHILE)); + + // for + KEYWORDS.Add(new PseudocodeType("BIS", FOR_TO)); + KEYWORDS.Add(new PseudocodeType("SCHRITT", FOR_STEP)); + KEYWORDS.Add(new PseudocodeType("IN", FOR_IN)); + KEYWORDS.Add(new PseudocodeType("ENDE FÜR", END_FOR)); } } } diff --git a/pseudocodeIde/interpreter/scanner/Scanner.cs b/pseudocodeIde/interpreter/scanner/Scanner.cs index cdf8f7b..b80eb54 100644 --- a/pseudocodeIde/interpreter/scanner/Scanner.cs +++ b/pseudocodeIde/interpreter/scanner/Scanner.cs @@ -29,12 +29,12 @@ public class Scanner /// /// User-written Pseudocode /// - private readonly string CODE; + private readonly string _code; /// /// The list of tokens that will be generated from the CODE. /// - private readonly LinkedList TOKENS = new LinkedList(); + private readonly LinkedList _tokens = new LinkedList(); /// /// start position of the current lexeme @@ -57,7 +57,7 @@ public class Scanner /// the Pseudocode text string public Scanner(string code) { - this.CODE = code; + this._code = code; } /// @@ -73,8 +73,8 @@ public LinkedList ScanTokens() ScanToken(); } - TOKENS.AddLast(Token.CreateEofToken(_line)); - return TOKENS; + _tokens.AddLast(Token.CreateEofToken(_line)); + return _tokens; } /// @@ -234,7 +234,7 @@ private void HandleIdentifier(bool textEmpty = true) Advance(); } - string text = CODE.Substring(_start, _current - _start); + string text = _code.Substring(_start, _current - _start); // allow something like "ENDE WENN"; when text is ENDE and the next char is a space, allow the space in the identifier if (textEmpty && text.Equals("ENDE") && (IsAtEnd() || Peek() == ' ' || Peek() == '\t')) @@ -297,7 +297,7 @@ private void HandleNumber() Advance(); } // start + 2 because the '0x' must be removed - AddToken(NUMBER, Convert.ToInt32(CODE.Substring(_start + 2, _current - _start), 16)); + AddToken(NUMBER, Convert.ToInt32(_code.Substring(_start + 2, _current - _start), 16)); return; } else if (Peek() == 'b' && IsBinaryDigit(PeekNext())) @@ -310,11 +310,11 @@ private void HandleNumber() Advance(); } // start + 2 because the '0b' must be removed - AddToken(NUMBER, Convert.ToInt32(CODE.Substring(_start, _current - _start).Substring(2), 2)); + AddToken(NUMBER, Convert.ToInt32(_code.Substring(_start, _current - _start).Substring(2), 2)); return; } - AddToken(NUMBER, double.Parse(CODE.Substring(_start, _current - _start))); + AddToken(NUMBER, double.Parse(_code.Substring(_start, _current - _start))); } /// @@ -357,7 +357,7 @@ private void HandleChar() Advance(); // trim the surrounding quotes - string value = CODE.Substring(_start + 1, _current - _start - 2); + string value = _code.Substring(_start + 1, _current - _start - 2); AddToken(CHAR, value); } @@ -386,7 +386,7 @@ private void HandleString() Advance(); // trim the surrounding quotes - string value = CODE.Substring(_start + 1, _current - _start - 2); + string value = _code.Substring(_start + 1, _current - _start - 2); AddToken(STRING, value); } @@ -402,7 +402,7 @@ private bool Match(char expected) return false; } - if (CODE[_current] != expected) + if (_code[_current] != expected) { return false; } @@ -418,7 +418,7 @@ private bool Match(char expected) /// private char Peek() { - return IsAtEnd() ? '\0' : CODE[_current]; + return IsAtEnd() ? '\0' : _code[_current]; } /// @@ -427,14 +427,14 @@ private char Peek() /// private char PeekNext() { - return _current + 1 >= CODE.Length ? '\0' : CODE[_current + 1]; + return _current + 1 >= _code.Length ? '\0' : _code[_current + 1]; } /// /// check if a char is a digit /// /// - private bool IsDigit(char c) + public static bool IsDigit(char c) { return c >= '0' && c <= '9'; } @@ -463,7 +463,7 @@ private bool IsBinaryDigit(char c) /// Check if a char is in the (German) alphabet /// /// - private bool IsAlpha(char c) + public static bool IsAlpha(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || @@ -476,7 +476,7 @@ private bool IsAlpha(char c) /// Check if a char is alphanumeric /// /// - private bool IsAlphaNumeric(char c) + public static bool IsAlphaNumeric(char c) { return IsAlpha(c) || IsDigit(c); } @@ -487,7 +487,7 @@ private bool IsAlphaNumeric(char c) /// private bool IsAtEnd() { - return _current >= CODE.Length; + return _current >= _code.Length; } /// @@ -496,7 +496,7 @@ private bool IsAtEnd() /// private char Advance() { - return CODE[_current++]; + return _code[_current++]; } /// @@ -506,8 +506,8 @@ private char Advance() /// the literal object private void AddToken(TokenType type, object literal = null) { - string text = CODE.Substring(_start, _current - _start); - TOKENS.AddLast(new Token(type, text, literal, _line)); + string text = _code.Substring(_start, _current - _start); + _tokens.AddLast(new Token(type, text, literal, _line)); } } } diff --git a/pseudocodeIde/interpreter/scanner/SyntaxHighlightingScanner.cs b/pseudocodeIde/interpreter/scanner/SyntaxHighlightingScanner.cs index 84cbb5b..21e3c3d 100644 --- a/pseudocodeIde/interpreter/scanner/SyntaxHighlightingScanner.cs +++ b/pseudocodeIde/interpreter/scanner/SyntaxHighlightingScanner.cs @@ -160,8 +160,6 @@ public static void Style(Scintilla scintilla, int startPos, int endPos) identifier = scintilla.GetTextRange(startPos - length, length); } - Debug.WriteLine($"'{identifier}'"); - int style = STYLE_IDENTIFIER; // if the identifier is in the keyword list, then it will has a differnt color if (PseudocodeKeywords.KEYWORDS.ContainsKey(identifier))