Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Crocker <dcrocker@eschertech.com>2021-03-10 12:19:35 +0300
committerDavid Crocker <dcrocker@eschertech.com>2021-03-10 12:19:35 +0300
commit8b89aab7455a870574fed653738af5566e82beb3 (patch)
treecf76a26591d12b45f629cff8c3b025fd64ea53db /src/GCodes/GCodeBuffer/StringParser.cpp
parentdd4939d6c393fba1ba1c101ad848562998b5ea09 (diff)
Implemented variables
Diffstat (limited to 'src/GCodes/GCodeBuffer/StringParser.cpp')
-rw-r--r--src/GCodes/GCodeBuffer/StringParser.cpp228
1 files changed, 151 insertions, 77 deletions
diff --git a/src/GCodes/GCodeBuffer/StringParser.cpp b/src/GCodes/GCodeBuffer/StringParser.cpp
index bdd6ead2..643a58a9 100644
--- a/src/GCodes/GCodeBuffer/StringParser.cpp
+++ b/src/GCodes/GCodeBuffer/StringParser.cpp
@@ -270,11 +270,11 @@ bool StringParser::LineFinished()
{
if (hadLineNumber)
{
- gb.machineState->lineNumber = receivedLineNumber;
+ gb.CurrentFileMachineState().lineNumber = receivedLineNumber;
}
else
{
- ++gb.machineState->lineNumber;
+ ++gb.CurrentFileMachineState().lineNumber;
}
if (gcodeLineEnd == 0)
@@ -289,7 +289,7 @@ bool StringParser::LineFinished()
if (gb.bufferState != GCodeBufferState::parsingComment) // we don't checksum comment lines
{
const bool badChecksum = (hadChecksum && computedChecksum != declaredChecksum);
- const bool missingChecksum = (checksumRequired && !hadChecksum && gb.machineState->GetPrevious() == nullptr);
+ const bool missingChecksum = (checksumRequired && !hadChecksum && gb.LatestMachineState().GetPrevious() == nullptr);
if (reprap.Debug(moduleGcodes) && fileBeingWritten == nullptr)
{
debugPrintf("%s%s: %s\n", gb.GetChannel().ToString(), ((badChecksum) ? "(bad-csum)" : (missingChecksum) ? "(no-csum)" : ""), gb.buffer);
@@ -306,7 +306,7 @@ bool StringParser::CheckMetaCommand(const StringRef& reply) THROWS(GCodeExceptio
{
if (overflowed)
{
- throw GCodeException(gb.MachineState().lineNumber, ARRAY_SIZE(gb.buffer) - 1, "GCode command too long");
+ throw GCodeException(gb.GetLineNumber(), ARRAY_SIZE(gb.buffer) - 1, "GCode command too long");
}
const bool doingFile = gb.IsDoingFile();
@@ -336,30 +336,30 @@ bool StringParser::CheckMetaCommand(const StringRef& reply) THROWS(GCodeExceptio
// Finished skipping the nested block
if (indentToSkipTo == commandIndent)
{
- skippedBlockType = gb.machineState->CurrentBlockState().GetType(); // save the type of the block we skipped in case the command is 'else' or 'elif'
- gb.machineState->CurrentBlockState().SetPlainBlock(); // we've ended the loop or if-block
+ skippedBlockType = gb.GetBlockState().GetType(); // save the type of the block we skipped in case the command is 'else' or 'elif'
+ gb.GetBlockState().SetPlainBlock(); // we've ended the loop or if-block
}
indentToSkipTo = NoIndentSkip; // no longer skipping
}
}
- while (commandIndent < gb.machineState->CurrentBlockIndent())
+ while (commandIndent < gb.GetBlockIndent())
{
- gb.machineState->EndBlock();
- if (gb.machineState->CurrentBlockState().GetType() == BlockType::loop)
+ gb.CurrentFileMachineState().EndBlock();
+ if (gb.GetBlockState().GetType() == BlockType::loop)
{
// Go back to the start of the loop and re-evaluate the while-part
- gb.machineState->lineNumber = gb.machineState->CurrentBlockState().GetLineNumber();
- gb.RestartFrom(gb.machineState->CurrentBlockState().GetFilePosition());
+ gb.CurrentFileMachineState().lineNumber = gb.GetBlockState().GetLineNumber();
+ gb.RestartFrom(gb.GetBlockState().GetFilePosition());
Init();
return true;
}
}
- if (commandIndent > gb.machineState->CurrentBlockIndent())
+ if (commandIndent > gb.GetBlockIndent())
{
// Indentation has increased so start new block(s)
- if (!gb.machineState->CreateBlock(commandIndent))
+ if (!gb.CurrentFileMachineState().CreateBlock(commandIndent))
{
throw ConstructParseException("blocks nested too deeply");
}
@@ -392,7 +392,7 @@ void StringParser::CheckForMixedSpacesAndTabs() noexcept
if (seenMetaCommand && !warnedAboutMixedSpacesAndTabs && seenLeadingSpace && seenLeadingTab)
{
reprap.GetPlatform().MessageF(AddWarning(gb.GetResponseMessageType()),
- "both space and tab characters used to indent blocks by line %" PRIu32, gb.MachineState().lineNumber);
+ "both space and tab characters used to indent blocks by line %" PRIu32, gb.GetLineNumber());
warnedAboutMixedSpacesAndTabs = true;
}
}
@@ -427,18 +427,15 @@ bool StringParser::ProcessConditionalGCode(const StringRef& reply, BlockType ski
break;
case 3:
- if (doingFile)
+ if (doingFile && StringStartsWith(command, "var"))
{
- if (StringStartsWith(command, "var"))
- {
- ProcessVarCommand();
- return true;
- }
- if (StringStartsWith(command, "set"))
- {
- ProcessSetCommand();
- return true;
- }
+ ProcessVarOrGlobalCommand(false);
+ return true;
+ }
+ if (StringStartsWith(command, "set"))
+ {
+ ProcessSetCommand();
+ return true;
}
break;
@@ -488,6 +485,14 @@ bool StringParser::ProcessConditionalGCode(const StringRef& reply, BlockType ski
}
break;
+ case 6:
+ if (StringStartsWith(command, "global"))
+ {
+ ProcessVarOrGlobalCommand(true);
+ return true;
+ }
+ break;
+
case 8:
if (doingFile && StringStartsWith(command, "continue"))
{
@@ -505,29 +510,29 @@ bool StringParser::ProcessConditionalGCode(const StringRef& reply, BlockType ski
return false;
}
-void StringParser::ProcessIfCommand()
+void StringParser::ProcessIfCommand() THROWS(GCodeException)
{
if (EvaluateCondition())
{
- gb.machineState->CurrentBlockState().SetIfTrueBlock();
+ gb.GetBlockState().SetIfTrueBlock();
}
else
{
- gb.machineState->CurrentBlockState().SetIfFalseNoneTrueBlock();
- indentToSkipTo = gb.machineState->CurrentBlockIndent(); // skip forwards to the end of the block
+ gb.GetBlockState().SetIfFalseNoneTrueBlock();
+ indentToSkipTo = gb.GetBlockIndent(); // skip forwards to the end of the block
}
}
-void StringParser::ProcessElseCommand(BlockType skippedBlockType)
+void StringParser::ProcessElseCommand(BlockType skippedBlockType) THROWS(GCodeException)
{
if (skippedBlockType == BlockType::ifFalseNoneTrue)
{
- gb.machineState->CurrentBlockState().SetPlainBlock(); // execute the else-block, treating it like a plain block
+ gb.GetBlockState().SetPlainBlock(); // execute the else-block, treating it like a plain block
}
- else if (skippedBlockType == BlockType::ifFalseHadTrue || gb.machineState->CurrentBlockState().GetType() == BlockType::ifTrue)
+ else if (skippedBlockType == BlockType::ifFalseHadTrue || gb.GetBlockState().GetType() == BlockType::ifTrue)
{
- indentToSkipTo = gb.machineState->CurrentBlockIndent(); // skip forwards to the end of the if-block
- gb.machineState->CurrentBlockState().SetPlainBlock(); // so that we get an error if there is another 'else' part
+ indentToSkipTo = gb.GetBlockIndent(); // skip forwards to the end of the if-block
+ gb.GetBlockState().SetPlainBlock(); // so that we get an error if there is another 'else' part
}
else
{
@@ -535,24 +540,24 @@ void StringParser::ProcessElseCommand(BlockType skippedBlockType)
}
}
-void StringParser::ProcessElifCommand(BlockType skippedBlockType)
+void StringParser::ProcessElifCommand(BlockType skippedBlockType) THROWS(GCodeException)
{
if (skippedBlockType == BlockType::ifFalseNoneTrue)
{
if (EvaluateCondition())
{
- gb.machineState->CurrentBlockState().SetIfTrueBlock();
+ gb.GetBlockState().SetIfTrueBlock();
}
else
{
- indentToSkipTo = gb.machineState->CurrentBlockIndent(); // skip forwards to the end of the elif-block
- gb.machineState->CurrentBlockState().SetIfFalseNoneTrueBlock();
+ indentToSkipTo = gb.GetBlockIndent(); // skip forwards to the end of the elif-block
+ gb.GetBlockState().SetIfFalseNoneTrueBlock();
}
}
- else if (skippedBlockType == BlockType::ifFalseHadTrue || gb.machineState->CurrentBlockState().GetType() == BlockType::ifTrue)
+ else if (skippedBlockType == BlockType::ifFalseHadTrue || gb.GetBlockState().GetType() == BlockType::ifTrue)
{
- indentToSkipTo = gb.machineState->CurrentBlockIndent(); // skip forwards to the end of the if-block
- gb.machineState->CurrentBlockState().SetIfFalseHadTrueBlock();
+ indentToSkipTo = gb.GetBlockIndent(); // skip forwards to the end of the if-block
+ gb.GetBlockState().SetIfFalseHadTrueBlock();
}
else
{
@@ -560,69 +565,138 @@ void StringParser::ProcessElifCommand(BlockType skippedBlockType)
}
}
-void StringParser::ProcessWhileCommand()
+void StringParser::ProcessWhileCommand() THROWS(GCodeException)
{
// Set the current block as a loop block first so that we may use 'iterations' in the condition
- if (gb.machineState->CurrentBlockState().GetType() == BlockType::loop)
+ if (gb.GetBlockState().GetType() == BlockType::loop)
{
- gb.machineState->CurrentBlockState().IncrementIterations(); // starting another iteration
+ gb.GetBlockState().IncrementIterations(); // starting another iteration
}
else
{
- gb.machineState->CurrentBlockState().SetLoopBlock(GetFilePosition(), gb.machineState->lineNumber);
+ gb.GetBlockState().SetLoopBlock(GetFilePosition(), gb.GetLineNumber());
}
if (!EvaluateCondition())
{
- gb.machineState->CurrentBlockState().SetPlainBlock();
- indentToSkipTo = gb.machineState->CurrentBlockIndent(); // skip forwards to the end of the block
+ gb.GetBlockState().SetPlainBlock();
+ indentToSkipTo = gb.GetBlockIndent(); // skip forwards to the end of the block
}
}
-void StringParser::ProcessBreakCommand()
+void StringParser::ProcessBreakCommand() THROWS(GCodeException)
{
do
{
- if (gb.machineState->CurrentBlockIndent() == 0)
+ if (gb.GetBlockIndent() == 0)
{
throw ConstructParseException("'break' was not inside a loop");
}
- gb.machineState->EndBlock();
- } while (gb.machineState->CurrentBlockState().GetType() != BlockType::loop);
- gb.machineState->CurrentBlockState().SetPlainBlock();
- indentToSkipTo = gb.machineState->CurrentBlockIndent(); // skip forwards to the end of the loop
+ gb.CurrentFileMachineState().EndBlock();
+ } while (gb.GetBlockState().GetType() != BlockType::loop);
+ gb.GetBlockState().SetPlainBlock();
+ indentToSkipTo = gb.GetBlockIndent(); // skip forwards to the end of the loop
}
-void StringParser::ProcessContinueCommand()
+void StringParser::ProcessContinueCommand() THROWS(GCodeException)
{
do
{
- if (gb.machineState->CurrentBlockIndent() == 0)
+ if (gb.GetBlockIndent() == 0)
{
throw ConstructParseException("'continue' was not inside a loop");
}
- gb.machineState->EndBlock();
- } while (gb.machineState->CurrentBlockState().GetType() != BlockType::loop);
+ gb.CurrentFileMachineState().EndBlock();
+ } while (gb.GetBlockState().GetType() != BlockType::loop);
// Go back to the start of the loop and re-evaluate the while-part
- gb.machineState->lineNumber = gb.machineState->CurrentBlockState().GetLineNumber();
- gb.RestartFrom(gb.machineState->CurrentBlockState().GetFilePosition());
+ gb.CurrentFileMachineState().lineNumber = gb.GetBlockState().GetLineNumber();
+ gb.RestartFrom(gb.GetBlockState().GetFilePosition());
}
-void StringParser::ProcessVarCommand()
+void StringParser::ProcessVarOrGlobalCommand(bool isGlobal) THROWS(GCodeException)
{
-#if 0
SkipWhiteSpace();
+
+ // Get the identifier
+ char c = gb.buffer[readPointer];
+ if (!isalpha(c))
+ {
+ throw ConstructParseException("expected a new variable name");
+ }
String<MaxVariableNameLength> varName;
- ParseIdentifier(varName.GetRef());
- qq;
-#endif
- throw ConstructParseException("'var' not implemented");
+ do
+ {
+ varName.cat(c);
+ ++readPointer;
+ c = gb.buffer[readPointer];
+ } while (isalpha(c) || isdigit(c) || c == '_' );
+
+ // Expect '='
+ SkipWhiteSpace();
+ if (gb.buffer[readPointer] != '=')
+ {
+ throw ConstructParseException("expected '='");
+ }
+ ++readPointer;
+
+ // Check whether the identifier already exists
+ VariableSet& vset = (isGlobal) ? reprap.globalVariables : gb.GetVariables();
+ Variable * const v = vset.Lookup(varName.c_str());
+ if (v != nullptr)
+ {
+ // For now we don't allow an existing variable to be reassigned using a 'var' or 'global' statement. We may need to allow it for 'global' statements.
+ throw ConstructParseException("variable '%s' already exists", varName.c_str());
+ }
+
+ SkipWhiteSpace();
+ ExpressionParser parser(gb, gb.buffer + readPointer, gb.buffer + ARRAY_SIZE(gb.buffer), commandIndent + readPointer);
+ ExpressionValue ev = parser.Parse();
+ vset.Insert(new Variable(varName.c_str(), ev, (isGlobal) ? 0 : gb.CurrentFileMachineState().GetBlockNesting()));
}
-void StringParser::ProcessSetCommand()
+void StringParser::ProcessSetCommand() THROWS(GCodeException)
{
- throw ConstructParseException("'set' not implemented");
+ // Skip the "var." or "global." prefix
+ SkipWhiteSpace();
+ VariableSet& vset = (StringStartsWith(gb.buffer + readPointer, "global.")) ? (readPointer += strlen("global."), reprap.globalVariables)
+ : (StringStartsWith(gb.buffer + readPointer, "var.")) ? (readPointer += strlen("var."), gb.GetVariables())
+ : throw ConstructParseException("expected a global or local variable");
+
+ // Get the identifier
+ char c = gb.buffer[readPointer];
+ if (!isalpha(c))
+ {
+ throw ConstructParseException("expected a new variable name");
+ }
+
+ String<MaxVariableNameLength> varName;
+ do
+ {
+ varName.cat(c);
+ ++readPointer;
+ c = gb.buffer[readPointer];
+ } while (isalpha(c) || isdigit(c) || c == '_' );
+
+ // Expect '='
+ SkipWhiteSpace();
+ if (gb.buffer[readPointer] != '=')
+ {
+ throw ConstructParseException("expected '='");
+ }
+ ++readPointer;
+
+ // Look up the identifier
+ Variable * const var = vset.Lookup(varName.c_str());
+ if (var == nullptr)
+ {
+ throw ConstructParseException("unknown variable '%s'", varName.c_str());
+ }
+
+ SkipWhiteSpace();
+ ExpressionParser parser(gb, gb.buffer + readPointer, gb.buffer + ARRAY_SIZE(gb.buffer), commandIndent + readPointer);
+ ExpressionValue ev = parser.Parse();
+ var->Assign(ev);
}
void StringParser::ProcessAbortCommand(const StringRef& reply) noexcept
@@ -870,7 +944,7 @@ void StringParser::SetFinished() noexcept
}
else
{
- gb.machineState->g53Active = false; // G53 does not persist beyond the current line
+ gb.LatestMachineState().g53Active = false; // G53 does not persist beyond the current line
Init();
}
}
@@ -879,13 +953,13 @@ void StringParser::SetFinished() noexcept
FilePosition StringParser::GetFilePosition() const noexcept
{
#if HAS_MASS_STORAGE
- if (gb.machineState->DoingFile()
+ if (gb.LatestMachineState().DoingFile()
# if HAS_LINUX_INTERFACE
&& !reprap.UsingLinuxInterface()
# endif
)
{
- return gb.machineState->fileState.GetPosition() - gb.fileInput->BytesCached() - commandLength + commandStart;
+ return gb.LatestMachineState().fileState.GetPosition() - gb.fileInput->BytesCached() - commandLength + commandStart;
}
#endif
return noFilePosition;
@@ -1439,7 +1513,7 @@ void StringParser::WriteToFile() noexcept
fileBeingWritten->Close();
fileBeingWritten = nullptr;
Init();
- const char* const r = (gb.MachineState().compatibility == Compatibility::Marlin) ? "Done saving file." : "";
+ const char* const r = (gb.LatestMachineState().compatibility == Compatibility::Marlin) ? "Done saving file." : "";
reprap.GetGCodes().HandleReply(gb, GCodeResult::ok, r);
return;
}
@@ -1502,7 +1576,7 @@ void StringParser::FinishWritingBinary() noexcept
binaryWriting = false;
if (crcOk)
{
- const char* const r = (gb.MachineState().compatibility == Compatibility::Marlin) ? "Done saving file." : "";
+ const char* const r = (gb.LatestMachineState().compatibility == Compatibility::Marlin) ? "Done saving file." : "";
reprap.GetGCodes().HandleReply(gb, GCodeResult::ok, r);
}
else
@@ -1549,12 +1623,12 @@ bool StringParser::FileEnded() noexcept
fileBeingWritten->Close();
fileBeingWritten = nullptr;
SetFinished();
- const char* const r = (gb.MachineState().compatibility == Compatibility::Marlin) ? "Done saving file." : "";
+ const char* const r = (gb.LatestMachineState().compatibility == Compatibility::Marlin) ? "Done saving file." : "";
reprap.GetGCodes().HandleReply(gb, GCodeResult::ok, r);
return false;
}
- if (!commandCompleted && gb.MachineState().GetIterations() >= 0)
+ if (!commandCompleted && gb.CurrentFileMachineState().GetIterations() >= 0)
{
// We reached the end of the file while inside a loop. Insert a dummy 'skip' command to allow the loop processing to complete.
Init();
@@ -1692,17 +1766,17 @@ void StringParser::SetParameters(VariableSet& vs, int codeRunning) noexcept
GCodeException StringParser::ConstructParseException(const char *str) const noexcept
{
- return GCodeException(gb.machineState->lineNumber, readPointer + commandIndent, str);
+ return GCodeException(gb.GetLineNumber(), readPointer + commandIndent, str);
}
GCodeException StringParser::ConstructParseException(const char *str, const char *param) const noexcept
{
- return GCodeException(gb.machineState->lineNumber, readPointer + commandIndent, str, param);
+ return GCodeException(gb.GetLineNumber(), readPointer + commandIndent, str, param);
}
GCodeException StringParser::ConstructParseException(const char *str, uint32_t param) const noexcept
{
- return GCodeException(gb.machineState->lineNumber, readPointer + commandIndent, str, param);
+ return GCodeException(gb.GetLineNumber(), readPointer + commandIndent, str, param);
}
// End