Jesse McGrew avatar Jesse McGrew committed 22244c2

Implemented 'include' directive
Fixed HASH/HASHHASH/HASHDOLLAR lexing

Comments (0)

Files changed (3)

Rellor.Core/Inform6.g3

 tokens {
     // emitted by lexer
     CHAR_LITERAL;
+	HASHHASH;
+	HASHDOLLAR;
     ARROW='->';
     DARROW='-->';
     COMMA=',';
 	DOT='.';
 	DOTDOT='..';
 	SUPERCLASS='::';
-	HASH='#';
-	HASHHASH='##';
 	LPAREN='(';
 	RPAREN=')';
 	LBRACE='{';
 	QUESTION='?';
 	AT='@';
 
+	// fake tokens for Include handling
+	BEGIN_INCLUDE;
+	END_INCLUDE;
+
     // emitted by parser
     INT;
     UMINUS;
 	OLD_OBJECTLOOP;
 	BLOCK;
 	CASE;
+	DIRECTIVE;
 
     OBJECT;
     NEARBY;
         (('e' | 'E') ('+'|'-')? DEC_DIGIT+)?
     ;
 
-HASHDOLLAR
-    :	'#' ('a'..'z') '$'
-    ;
+HASH
+    :	'#'
+		(	/* nada */
+		|	'#'										{$type = HASHHASH;}
+		|	{input.LA(2)=='$'}?=> ('a'..'z') '$'	{$type = HASHDOLLAR;}
+		)
+	;
 
 ICL_COMMENT
-	:	{allowIcl}? '!' '%' ~('\n'|'\r')* '\r'? '\n' { $channel = IclChannel; }
+	:	{allowIcl}? '!' '%' ~('\n'|'\r')* '\r'? '\n' {$channel = IclChannel;}
 	;
 
 COMMENT
-	:	'!' ~('\n'|'\r')* '\r'? '\n' { $channel = CommentChannel; }
+	:	'!' ~('\n'|'\r')* '\r'? '\n' {$channel = CommentChannel;}
     ;
 
 SQ_STRING
     :	('0'..'1')
     ;
 
-fragment CHAR_LITERAL : ;	// suppress warning
-
 ID	:	('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
         { keyword = LookupKeyword($text); }
     ;
 
+// suppress warnings
+fragment CHAR_LITERAL : ;
+fragment BEGIN_INCLUDE : ;
+fragment END_INCLUDE : ;
+fragment HASHHASH : ;
+fragment HASHDOLLAR : ;
+
 /********************************** KEYWORDS **********************************/
 
 kBOX : {((RellorToken)input.LT(1)).Keyword == BOX}? ID -> BOX[$ID];
 scope { IScope globalScope; }
 scope Symbols, Quirks;
 @init { $program::globalScope = $Symbols::scope = new GlobalScope(); }
-    :	('#'!? directive[false] ';'!)*
+    :	(HASH!? directive[false])*
     ;
 
 directive[bool nested]
     |	global_directive
 		{DefineSymbol($Symbols::scope, SymbolType.GlobalVar, $global_directive.name, $global_directive.tree);}
     |	verb_directive
+	|	BEGIN_INCLUDE
+	|	END_INCLUDE
     ;
 
 include_directive
-    :	kINCLUDEci fn=DQ_STRING
+    :	kINCLUDEci^ fn=DQ_STRING ';'!
+		{IncludeFile(ParseDqString($fn.text));}
     ;
 
 version_directive
-    :	kVERSIONci^ number
+    :	kVERSIONci^ number ';'!
     ;
 
 release_directive
-    :	kRELEASEci^ number
+    :	kRELEASEci^ number ';'!
     ;
 
 serial_directive
-    :	kSERIALci^ DQ_STRING
+    :	kSERIALci^ DQ_STRING ';'!
     ;
 
 object_directive returns [ITree name]
-    :	kOBJECTci
-        ARROW*
-        n=id									// object identifier
-		{$name = $n.tree;}
-        sn=DQ_STRING?							// textual short name
-        p=id_not_seg?							// parent object
-        object_parts
-        -> ^(kOBJECTci $n ^(DEPTH ARROW*)? ^(SHORT_NAME $sn)? ^(PARENT $p)? object_parts)
-    |	kNEARBYci
-        n=id
-        sn=DQ_STRING?
-        p=id_not_seg?
-        object_parts
-        -> ^(OBJECT[$kNEARBYci.start] $n ^(DEPTH ARROW) ^(SHORT_NAME $sn)? ^(PARENT $p)? object_parts)
-    |	kCLASSci
-        n=id
-        object_parts
-        -> ^(kCLASSci $n object_parts)
+	:   (	kOBJECTci
+			ARROW*
+			n=id									// object identifier
+			{$name = $n.tree;}
+			sn=DQ_STRING?							// textual short name
+			p=id_not_seg?							// parent object
+			object_parts
+			-> ^(kOBJECTci $n ^(DEPTH ARROW*)? ^(SHORT_NAME $sn)? ^(PARENT $p)? object_parts)
+		|	kNEARBYci
+			n=id
+			sn=DQ_STRING?
+			p=id_not_seg?
+			object_parts
+			-> ^(OBJECT[$kNEARBYci.start] $n ^(DEPTH ARROW) ^(SHORT_NAME $sn)? ^(PARENT $p)? object_parts)
+		|	kCLASSci
+			n=id
+			object_parts
+			-> ^(kCLASSci $n object_parts)
+		)
+		';'
     ;
 
 object_parts
 		STAR?
 		(l+=id {DefineSymbol($routineScope, SymbolType.LocalVar, l.Tree);})* SEMI
 		switch_body
-		RSQUARE
+		RSQUARE ';'
 		-> ^(ROUTINE[$LSQUARE] $n ^(FLAGS STAR?)? ^(LOCALS $l*)? switch_body)
     ;
 
 array_directive returns [ITree name]
-    :	kARRAYci^ n=id array_initializer
+    :	kARRAYci^ n=id array_initializer ';'
 		{$name = $n.tree;}
     ;
 
         |	array_initializer
             -> ^(kGLOBALci $n ^(ARRAY array_initializer))
         )
+		';'
     ;
 
 verb_directive
         (	EQ (vx=DQ_STRING|vx=SQ_STRING)
         |	grammar_line+
         )
+		';'
         -> ^(VERB ^(FLAGS kMETA?)? ^(SLASH $v+) ^(EQ $vx)? grammar_line*)
     ;
 
     |	jump_stmt
     |	assembly_stmt
     |	action_stmt	
+    |	(directive_stmt)=> directive_stmt
     |	expr_stmt
-    |	directive_stmt
     |	label
     |	block
     |	null_stmt
+	|	BEGIN_INCLUDE
+	|	END_INCLUDE
     ;
     
 print_stmt
     ;
 
 directive_stmt
-    :	'#'^ directive[true] ';'!
+    :	HASH directive[true]	/* directive already includes ';' */
+		-> ^(DIRECTIVE directive)
     ;
 
 null_stmt
 simple_constant
     :	number
     |	id
+	|	HASH^ id
+	|	HASHHASH^ id
     |	HASHDOLLAR^ id
     |	SQ_STRING^
     |	DQ_STRING^

Rellor.Core/Inform6.g3.parser.cs

 using Antlr.Runtime.Tree;
 using Rellor.Core.Token;
 using Rellor.Core.Tree;
+using System.Linq;
+using System.Text;
 
 namespace Rellor.Core
 {
             return (int)str[1];
         }
 
+        private static string ParseDqString(string str)
+        {
+            Contract.Requires(str != null);
+            Contract.Requires(str.Length >= 2);
+
+            var sb = new StringBuilder(str, 1, str.Length - 2, str.Length - 2);
+            for (int i = 0; i < sb.Length; i++)
+                switch (sb[i])
+                {
+                    case '^':
+                        sb[i] = '\n';
+                        break;
+                    case '~':
+                        sb[i] = '"';
+                        break;
+                }
+
+            return sb.ToString();
+        }
+
+        private static string ParseSqString(string str)
+        {
+            Contract.Requires(str != null);
+            Contract.Requires(str.Length >= 2);
+
+            var sb = new StringBuilder(str, 1, str.Length - 2, str.Length - 2);
+            for (int i = 0; i < sb.Length; i++)
+                switch (sb[i])
+                {
+                    case '^':
+                        sb[i] = '\'';
+                        break;
+                }
+
+            // TODO: handle '//' stuff at end?
+
+            return sb.ToString();
+        }
+
         private static bool IsKeyword(RellorToken token, int kw1, int kw2 = -2, int kw3 = -2, int kw4 = -2)
         {
             Contract.Requires(token != null);
         {
             adaptor = new RellorTreeAdaptor();
         }
+
+        private void IncludeFile(string filespec)
+        {
+            //XXX include file
+            var stream = new ANTLRStringStream(filespec);
+            InsertTokens(stream, "literal");
+        }
+
+        private void InsertTokens(ICharStream charStream, string sourceName)
+        {
+            Contract.Requires(charStream != null);
+            Contract.Requires(sourceName != null);
+
+            var thatStream = new RellorTokenStream(new Inform6Lexer(charStream));
+            thatStream.Fill();
+            var thoseTokens = thatStream.GetTokens();
+
+            var beginning = Enumerable.Repeat(new RellorToken(BEGIN_INCLUDE, sourceName), 1);
+            var middle = thoseTokens.Take(thoseTokens.Count - 1);   // skip EOF
+            var end = Enumerable.Repeat(new RellorToken(END_INCLUDE, sourceName), 1);
+
+            var includedTokens = Enumerable.Concat(Enumerable.Concat(beginning, middle), end);
+
+            var thisStream = (RellorTokenStream)input;
+            thisStream.GetTokens().InsertRange(thisStream.Index, includedTokens);
+        }
     }
 }

Rellor.Core/Rellor.Core.csproj

     <Compile Include="SpecializeOperators.g3.cs">
       <DependentUpon>SpecializeOperators.g3</DependentUpon>
     </Compile>
-    <Compile Include="Tree\StringTree.cs" />
   </ItemGroup>
   <ItemGroup>
     <Antlr3 Include="Inform6.g3">
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.