@@ -684,16 +684,66 @@ 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
+ while ((c = parseVarSubst (string , c )) == '$' );
729
+
730
+ return c ;
731
+ }
732
+
687
733
/* Read a C identifier beginning with "firstChar" and places it into "name".
688
734
*/
689
735
static void parseIdentifier (vString * const string , const int firstChar )
690
736
{
691
737
int c = firstChar ;
692
- Assert (isIdentChar1 (c ));
738
+ Assert (vStringLength ( string ) > 0 || isIdentChar1 (c ));
693
739
do
694
740
{
695
741
vStringPut (string , c );
696
742
c = getcFromInputFile ();
743
+
744
+ /* Handle ${var} in HiveQL. */
745
+ if (c == '$' )
746
+ c = parseVarSubstSequence (string , c );
697
747
} while (isIdentChar (c ));
698
748
if (!isspace (c ))
699
749
ungetcToInputFile (c ); /* unget non-identifier character */
@@ -937,15 +987,23 @@ static void readToken (tokenInfo *const token)
937
987
}
938
988
939
989
case '$' :
940
- token -> type = parseDollarQuote (token -> string , c , & token -> promise );
941
- token -> lineNumber = getInputLineNumber ();
942
- token -> filePosition = getInputFilePosition ();
943
- break ;
990
+ {
991
+ int c0 = getcFromInputFile ();
992
+ ungetcToInputFile (c0 );
993
+ if (c0 != '{' )
994
+ {
995
+ token -> type = parseDollarQuote (token -> string , c , & token -> promise );
996
+ token -> lineNumber = getInputLineNumber ();
997
+ token -> filePosition = getInputFilePosition ();
998
+ break ;
999
+ }
1000
+ c = parseVarSubstSequence (token -> string , c );
1001
+ /* FALL THROUGH */
1002
+ }
944
1003
945
1004
default :
946
- if (! isIdentChar1 (c ))
947
- token -> type = TOKEN_UNDEFINED ;
948
- else
1005
+ if ( isIdentChar1 (c )
1006
+ || (vStringLength (token -> string ) > 0 && isIdentChar (c )))
949
1007
{
950
1008
parseIdentifier (token -> string , c );
951
1009
token -> lineNumber = getInputLineNumber ();
@@ -962,6 +1020,18 @@ static void readToken (tokenInfo *const token)
962
1020
else
963
1021
token -> type = TOKEN_KEYWORD ;
964
1022
}
1023
+ else if (vStringLength (token -> string ) > 0 )
1024
+ {
1025
+ ungetcToInputFile (c );
1026
+
1027
+ /* token->string may be ${var}.
1028
+ * We regard ${var} as an identifier. */
1029
+ token -> type = TOKEN_IDENTIFIER ;
1030
+ token -> lineNumber = getInputLineNumber ();
1031
+ token -> filePosition = getInputFilePosition ();
1032
+ }
1033
+ else
1034
+ token -> type = TOKEN_UNDEFINED ;
965
1035
break ;
966
1036
}
967
1037
}
0 commit comments