@@ -684,16 +684,68 @@ static void parseString (vString *const string, const int delimiter, int *promis
684
684
}
685
685
}
686
686
687
+ /* Parsing ${foo}.
688
+ *
689
+ * HiveQL is one of implementation having the variable substitution feature.
690
+ * https://cwiki.apache.org/confluence/display/Hive/LanguageManual+VariableSubstitution
691
+ */
692
+ static int parseVarSubstSequence (vString * const string , const int firstChar );
693
+ static int parseVarSubst (vString * const string , const int firstChar )
694
+ {
695
+ int c = firstChar ;
696
+ Assert (c == '$' );
697
+ vStringPut (string , c );
698
+
699
+ c = getcFromInputFile ();
700
+ if (c != '{' )
701
+ return c ;
702
+ vStringPut (string , c );
703
+
704
+ while ((c = getcFromInputFile ())!= EOF )
705
+ {
706
+ if (c == '}' )
707
+ {
708
+ vStringPut (string , c );
709
+ c = getcFromInputFile ();
710
+ return c ;
711
+ }
712
+ else if (c == '$' )
713
+ {
714
+ c = parseVarSubstSequence (string , c );
715
+ ungetcToInputFile (c );
716
+ }
717
+ else
718
+ vStringPut (string , c );
719
+ }
720
+
721
+ return c ;
722
+ }
723
+
724
+ static int parseVarSubstSequence (vString * const string , const int firstChar )
725
+ {
726
+ int c ;
727
+
728
+ do
729
+ c = parseVarSubst (string , c );
730
+ while (c == '$' );
731
+
732
+ return c ;
733
+ }
734
+
687
735
/* Read a C identifier beginning with "firstChar" and places it into "name".
688
736
*/
689
737
static void parseIdentifier (vString * const string , const int firstChar )
690
738
{
691
739
int c = firstChar ;
692
- Assert (isIdentChar1 (c ));
740
+ Assert (vStringLength ( string ) > 0 || isIdentChar1 (c ));
693
741
do
694
742
{
695
743
vStringPut (string , c );
696
744
c = getcFromInputFile ();
745
+
746
+ /* Handle ${var} in HiveQL. */
747
+ if (c == '$' )
748
+ c = parseVarSubstSequence (string , c );
697
749
} while (isIdentChar (c ));
698
750
if (!isspace (c ))
699
751
ungetcToInputFile (c ); /* unget non-identifier character */
@@ -937,15 +989,23 @@ static void readToken (tokenInfo *const token)
937
989
}
938
990
939
991
case '$' :
940
- token -> type = parseDollarQuote (token -> string , c , & token -> promise );
941
- token -> lineNumber = getInputLineNumber ();
942
- token -> filePosition = getInputFilePosition ();
943
- break ;
992
+ {
993
+ int c0 = getcFromInputFile ();
994
+ ungetcToInputFile (c0 );
995
+ if (c0 != '{' )
996
+ {
997
+ token -> type = parseDollarQuote (token -> string , c , & token -> promise );
998
+ token -> lineNumber = getInputLineNumber ();
999
+ token -> filePosition = getInputFilePosition ();
1000
+ break ;
1001
+ }
1002
+ c = parseVarSubstSequence (token -> string , c );
1003
+ /* FALL THROUGH */
1004
+ }
944
1005
945
1006
default :
946
- if (! isIdentChar1 (c ))
947
- token -> type = TOKEN_UNDEFINED ;
948
- else
1007
+ if ( isIdentChar1 (c )
1008
+ || (vStringLength (token -> string ) > 0 && isIdentChar (c )))
949
1009
{
950
1010
parseIdentifier (token -> string , c );
951
1011
token -> lineNumber = getInputLineNumber ();
@@ -962,6 +1022,18 @@ static void readToken (tokenInfo *const token)
962
1022
else
963
1023
token -> type = TOKEN_KEYWORD ;
964
1024
}
1025
+ else if (vStringLength (token -> string ) > 0 )
1026
+ {
1027
+ ungetcToInputFile (c );
1028
+
1029
+ /* token->string may be ${var}.
1030
+ * We regard ${var} as an identifier. */
1031
+ token -> type = TOKEN_IDENTIFIER ;
1032
+ token -> lineNumber = getInputLineNumber ();
1033
+ token -> filePosition = getInputFilePosition ();
1034
+ }
1035
+ else
1036
+ token -> type = TOKEN_UNDEFINED ;
965
1037
break ;
966
1038
}
967
1039
}
0 commit comments