diff --git a/src/notcl.ts b/src/notcl.ts
index 4fff10b..6b99b34 100644
--- a/src/notcl.ts
+++ b/src/notcl.ts
@@ -6,6 +6,7 @@ import {
   TextWord,
   EnchantedWord as EnchantedWordType,
   SimplifyWord,
+  InterpolatedPiece,
 } from "./words";
 
 const Comment = Regex(/#[^\n]*/y)
@@ -22,23 +23,27 @@ const BackslashEscape = Regex(/\\(.)/y)
   .expects("\\")
   .map(([, char]) => ({ text: char }));
 
-const BareWord = Sequence(
-  AtLeast(
-    1,
-    Choose(
-      BackslashEscape,
-      Regex(/[^\s\\;]+/y)
-        .expects("CHAR")
-        .map(([text]) => ({ text }))
+const BARE_WORD_CHAR = /[^\s\\;]+/y;
+
+function bareWordTmpl(charRegex: RegExp) {
+  return Sequence(
+    AtLeast(
+      1,
+      Choose<InterpolatedPiece>(
+        BackslashEscape,
+        Regex(charRegex)
+          .expects("CHAR")
+          .map(([text]) => ({ text }))
+      )
     )
-  )
-).map(([pieces]) => SimplifyWord(pieces));
+  ).map(([pieces]) => SimplifyWord(pieces));
+}
 
 const QuotedWord = Sequence(
   Regex(/"/y).expects('"'),
   AtLeast(
     0,
-    Choose(
+    Choose<InterpolatedPiece>(
       BackslashEscape,
       Regex(/[^"\\]+/y)
         .expects("CHAR")
@@ -67,40 +72,50 @@ const Brace: Pattern<string> = Sequence(
   Regex(/\}/y).expects("}")
 ).map(([, fragments]) => fragments.join(""));
 
-const Word = Choose<WordType>(
-  EnchantedWord,
-  Brace.map((text) => ({ text } as TextWord)),
-  QuotedWord,
-  BareWord
-);
+function wordTmpl(bareWordCharRegex: RegExp): Pattern<WordType> {
+  return Choose<WordType>(
+    EnchantedWord,
+    Brace.map((text) => ({ text } as TextWord)),
+    QuotedWord,
+    bareWordTmpl(bareWordCharRegex)
+  );
+}
 
 const CommandTerminator = Regex(/[\n;]/y)
   .expects("NEWLINE | ;")
   .map(() => true);
 
-const Command = Sequence(
-  Word,
-  AtLeast(
-    0,
-    Sequence(PreWordWhitespace, Word).map(([, word]) => word)
-  ),
-  AtLeast(0, PreWordWhitespace)
-).map(([word, moreWords]) => [word].concat(moreWords));
+function commandTmpl(bareWordCharRegex: RegExp) {
+  const word = wordTmpl(bareWordCharRegex);
+  return Sequence(
+    word,
+    AtLeast(
+      0,
+      Sequence(PreWordWhitespace, word).map(([, word]) => word)
+    ),
+    AtLeast(0, PreWordWhitespace)
+  ).map(([word, moreWords]) => [word].concat(moreWords));
+}
 
-const Script = Sequence(
-  AtLeast(
-    0,
-    Choose(
-      PreWordWhitespace.map(() => []),
-      CommandTerminator.map(() => []),
-      Sequence(Comment, Choose(CommandTerminator, End())).map(() => []),
-      Sequence(Command, Choose(CommandTerminator, End())).map(
-        ([words]) => words
+function scriptTmpl(bareWordCharRegex: RegExp, endPattern: Pattern<unknown>) {
+  return Sequence(
+    AtLeast(
+      0,
+      Choose(
+        PreWordWhitespace.map(() => []),
+        CommandTerminator.map(() => []),
+        Sequence(Comment, Choose(CommandTerminator, endPattern)).map(() => []),
+        Sequence(
+          commandTmpl(bareWordCharRegex),
+          Choose(CommandTerminator, endPattern)
+        ).map(([words]) => words)
       )
-    )
-  ),
-  End()
-).map(([commands]) => commands.filter((command) => command.length > 0));
+    ),
+    endPattern
+  ).map(([commands]) => commands.filter((command) => command.length > 0));
+}
+
+const Script = scriptTmpl(BARE_WORD_CHAR, End());
 
 const ERROR_CONTEXT = /(?<=([^\n]{0,50}))([^\n]{0,50})/y;