// ( -- ) Starts compilation of a colon definition public void compileColon(ref GlobalSimpleProps gsp) { int hereLoc = gsp.Cfb.Address.Count; string name = gsp.ParsedInput[gsp.OuterPtr + 1]; List <int> paramList = new List <int>(); List <object> data = new List <object>(); string help = "TODO: "; string rawWord = ""; int searchVocabPtr = 0; bool isFound = false; string compAction = ""; CompileInfo compInfo; bool isSemiPresent = false; int colonIndex = -1; Codefield codefield; CreoleWord cw; // I have to do a deep copy here GlobalSimpleProps gspComp = gspDeepCopy(gsp); // Elementary syntax check - if a colon isn't followed by a matching semicolon, you get an error message and the stacks and input are cleared. for (int i = 0; i < gsp.ParsedInput.Count; i++) { if (gsp.ParsedInput[i] == ":") { colonIndex = i; } if (gsp.ParsedInput[i] == ";" && i > colonIndex) { isSemiPresent = true; } } if (isSemiPresent == false) { Debug.Print("Error: colon def must have matching semicolon"); gsp.cleanFields(); return; } // Compilation is started when the IMMEDIATE vocabulary is pushed onto the vocabulary stack. No need for the usual Forth STATE flag. gsp.VocabStack.Add(gsp.BFC.ImmediateVocab); cw = new CreoleWord(name, gsp.Cfb.Modules.Interpreter.doColon, "Interpreter.doColon", gsp.CurrentVocab, "COMPINPF", help, hereLoc - 1, hereLoc, hereLoc - 1, hereLoc, paramList, data); // The smudge flag avoids accidental recursion. But it's easy enough to get around if you want to. string fqNameSmudged = name + "." + gsp.CurrentVocab + "." + gsp.BFC.SmudgeFlag; string fqName = name + "." + gsp.CurrentVocab; string fqWord = ""; gsp.Cfb.Dict[fqNameSmudged] = cw; gsp.Cfb.Address.Add(gsp.Cfb.Dict[fqNameSmudged]); gsp.OuterPtr += 2; // Parameter field contents are set up in the PAD area. Each word is looked up one at a time in the dictionary, and its name, address, and // compilation action are placed in the CompileInfo triplet. while (gsp.OuterPtr < gsp.ParsedInput.Count && gsp.VocabStack[gsp.VocabStack.Count - 1] == gsp.BFC.ImmediateVocab && gsp.ParsedInput[gsp.OuterPtr] != ";") { rawWord = gsp.ParsedInput[gsp.OuterPtr]; searchVocabPtr = gsp.VocabStack.Count - 1; isFound = false; while (searchVocabPtr >= 0) { fqWord = rawWord.ToUpper() + "." + gsp.VocabStack[searchVocabPtr]; if (gsp.Cfb.Dict.ContainsKey(fqWord)) { cw = gsp.Cfb.Dict[fqWord]; compAction = cw.CompileActionField; if (compAction != gsp.BFC.ExecZeroAction) { compInfo = new CompileInfo(fqWord, cw.IndexField, compAction); gsp.PADarea.Add(compInfo); } else { // This is stuff where the outer ptr is manipulated such as comments codefield = cw.CodeField; codefield(ref gsp); } isFound = true; break; } else { searchVocabPtr--; } } // If no dictionary entry is found, it's tagged as a literal. if (isFound == false) { compInfo = new CompileInfo(rawWord, rawWord, gsp.BFC.CompLitAction); gsp.PADarea.Add(compInfo); } gsp.OuterPtr++; // 1. Builds the definition in the parameter field from the PAD area. Very simple; the address of each word appears before its associated // compilation action. Most of the time, it will be COMPINPF, which will simply compile the word into the parameter field (it's actually // , (comma) with a different name for readability purposes). // Compiling words such as CompileIf will execute since that's the compilation action they're tagged with. // 2. Attaches it to the smudged definition. // 3. "Unsmudges" the new definition by copying it to its proper fully-qualified property and places it in the Address array. // 4. Deletes the smudged definition. // 5. Pops the IMMEDIATE vocabulary off the vocabulary stack and halts compilation int i = 0; gspComp.VocabStack = gsp.VocabStack; gspComp.Cfb.Address.Add(gsp.Cfb.Dict[fqNameSmudged]); // Putting the args and compilation actions together then executing them seems to cause a problem with compiling words. // Getting around this by putting one arg on the stack, one in the input area, then executing. while (i < gsp.PADarea.Count) { compInfo = gsp.PADarea[i]; gspComp.DataStack.Add(compInfo.Address); gspComp.InputArea = compInfo.CompileAction; gspComp.Cfb.Modules.Interpreter.doParseInput(ref gspComp); gspComp.Cfb.Modules.Interpreter.doOuter(ref gspComp); i++; } gspComp.InputArea = ";"; gspComp.Cfb.Modules.Interpreter.doParseInput(ref gspComp); gspComp.Cfb.Modules.Interpreter.doOuter(ref gspComp); cw = gspComp.Cfb.Address[hereLoc]; gsp.Cfb.Dict[fqName] = cw; gsp.Cfb.Dict.Remove(fqNameSmudged); } }