whole_func_string: function() {
      let ch = this.input();
      if (ch === "$") {
        ch = this.input();
        if (ch === "{") {
          this.begin("ST_LOOKING_FOR_VARNAME");
          return this.tok.T_DOLLAR_OPEN_CURLY_BRACES;
        } else if (this.is_LABEL_START()) {
          const tok = this.consume_VARIABLE();
          return tok;
        }
      } else if (ch === "{") {
        if (this._input[this.offset] === "$") {
          this.begin("ST_IN_SCRIPTING");
          return this.tok.T_CURLY_OPEN;
        }
      } else if (ch === "`") {
        this.popState();
        return "`";
      }
  
      // any char
      while (this.offset < this.size) {
        if (ch === "\\") {
          this.input();
        } else if (ch === "`") {
          this.unput(1);
          this.popState();
          this.appendToken("`", 1);
          break;
        } else if (ch === "$") {
          ch = this.input();
          if (ch === "{") {
            this.begin("ST_LOOKING_FOR_VARNAME");
            if (this.yytext.length > 2) {
              this.appendToken(this.tok.T_DOLLAR_OPEN_CURLY_BRACES, 2);
              this.unput(2);
              return this.tok.T_ENCAPSED_AND_WHITESPACE;
            } else {
              return this.tok.T_DOLLAR_OPEN_CURLY_BRACES;
            }
          } else if (this.is_LABEL_START()) {
            // start of $var...
            const yyoffset = this.offset;
            const next = this.consume_VARIABLE();
            if (this.yytext.length > this.offset - yyoffset + 2) {
              this.appendToken(next, this.offset - yyoffset + 2);
              this.unput(this.offset - yyoffset + 2);
              return this.tok.T_ENCAPSED_AND_WHITESPACE;
            } else {
              return next;
            }
          }
          continue;
        } else if (ch === "{") {
          ch = this.input();
          if (ch === "$") {
            // start of {$...
            this.begin("ST_IN_SCRIPTING");
            if (this.yytext.length > 2) {
              this.appendToken(this.tok.T_CURLY_OPEN, 1);
              this.unput(2);
              return this.tok.T_ENCAPSED_AND_WHITESPACE;
            } else {
              this.unput(1);
              return this.tok.T_CURLY_OPEN;
            }
          }
          continue;
        }
        ch = this.input();
      }
      return this.tok.T_ENCAPSED_AND_WHITESPACE;
    }
func_code_string: function() {
      let ch = this.input();
      if (ch === "$") {
        ch = this.input();
        if (ch === "{") {
          this.begin("ST_LOOKING_FOR_VARNAME");
          return this.tok.T_DOLLAR_OPEN_CURLY_BRACES;
        } else if (this.is_LABEL_START()) {
          const tok = this.consume_VARIABLE();
          return tok;
        }
      } else if (ch === "{") {
        if (this._input[this.offset] === "$") {
          this.begin("ST_IN_SCRIPTING");
          return this.tok.T_CURLY_OPEN;
        }
      } else if (ch === "`") {
        this.popState();
        return "`";
      }
  
      // any char
      while (this.offset < this.size) {
        if (ch === "\\") {
          this.input();
        } else if (ch === "`") {
          this.unput(1);
          this.popState();
          this.appendToken("`", 1);
          break;
        } else if (ch === "$") {
          ch = this.input();
          if (ch === "{") {
            this.begin("ST_LOOKING_FOR_VARNAME");
            if (this.yytext.length > 2) {
              this.appendToken(this.tok.T_DOLLAR_OPEN_CURLY_BRACES, 2);
              this.unput(2);
              return this.tok.T_ENCAPSED_AND_WHITESPACE;
            } else {
              return this.tok.T_DOLLAR_OPEN_CURLY_BRACES;
            }
          } else if (this.is_LABEL_START()) {
            // start of $var...
            const yyoffset = this.offset;
            const next = this.consume_VARIABLE();
            if (this.yytext.length > this.offset - yyoffset + 2) {
              this.appendToken(next, this.offset - yyoffset + 2);
              this.unput(this.offset - yyoffset + 2);
              return this.tok.T_ENCAPSED_AND_WHITESPACE;
            } else {
              return next;
            }
          }
          continue;
        } else if (ch === "{") {
          ch = this.input();
          if (ch === "$") {
            // start of {$...
            this.begin("ST_IN_SCRIPTING");
            if (this.yytext.length > 2) {
              this.appendToken(this.tok.T_CURLY_OPEN, 1);
              this.unput(2);
              return this.tok.T_ENCAPSED_AND_WHITESPACE;
            } else {
              this.unput(1);
              return this.tok.T_CURLY_OPEN;
            }
          }
          continue;
        }
        ch = this.input();
      }
      return this.tok.T_ENCAPSED_AND_WHITESPACE;
    }
func_documentation_string: HANDLES BACKQUOTES