Here's something that "emulates" SyntaxQ
. I've named it IsExpression
. It works by recursively identifying legal sub-expressions and sequences. Since you're not interested in syntactic sugar, it assumes full form expressions. I am not confident that this is complete or correct for all cases, but maybe it's a sufficiently decent approximation.
ReduceExpressionStep[token_String][exp_String] :=
With[
{NumberPattern =
RegularExpression["(\\d+\\.\\d+)|(\\d+\\.)|(\\.\\d+)|(\\d+)"],
StringPattern = RegularExpression["\"[^\"]\""],
SymbolPattern = RegularExpression["[[:alpha:]]+"],
HeadedPattern = "$[]",
SequencePattern = RegularExpression["\\[(\\$,)*\\$\\]"]},
StringReplace[
StringDelete[exp, Whitespace],
{NumberPattern -> token,
StringPattern -> token,
SymbolPattern -> token,
HeadedPattern -> token,
SequencePattern -> ""}]];
ReduceExpression[token_String][exp_String] :=
FixedPoint[ReduceExpressionStep[token], exp];
IsExpression[exp_String] := "$" == ReduceExpression["$"][exp]