# File kwartz.rb, line 3375
        def parse_stmt_list
            list = []
            while (method_symbol = METHOD_DISPATHER[token()]) != nil do
                node = self.__send__(method_symbol)
                if method_symbol == :parse_stmt_load
                    nodelist = node
                    list.concat(nodelist.list)
                else
                    stmt_node = node
                    list << stmt_node
                end
            end
            return NodeList.new(list)
        end


        ##
        ## * BNF:
        ##    set-stmt ::= ':set' '(' assignment ')'
        ##
        ## * return node:
        ##   token::  :set
        ##   left::   assignment ExprNode
        ##   right::  nil
        ##
        def parse_stmt_set
            Kwartz::assert() unless token() == :set
            scan()
            _syntaxerr("':set' requires '('.") unless token() == '('
            scan()
            expr = parse_assignment()
            _syntaxerr("':set(' is not closed by ')'.") unless token() == ')'
            scan()
            _syntaxerr("':set' requires assignment.") unless _assign_op?(expr.token)
            return SetStmtNode.new(:set, expr, nil)
        end


        ##
        ## * BNF:
        ##    if-stmt ::= ':if' '(' expression ')' stmt-list 
        ##              { ':elsif' '(' expression ')' stmt-list }
        ##              [ ':else' stmt-list ] ':end'
        ##
        ## * return node
        ##   token::     :if
        ##   left::      NodeList
        ##   right::     if StmtNode (when :elsif) / NodeList (when no :elsif)
        ##   condition::  ExprNode
        ##
        def parse_stmt_if
            Kwartz::assert() unless token() == :if || token() == :elsif
            t = token()
            scan()
            _syntaxerr("':#{t.id2name}' requires '('.") unless token() == '('
            scan()
            cond_expr = parse_expression()
            _syntaxerr("':#{t.id2name}(' is not closed by ')'.") unless token() == ')'
            scan()
            then_node = parse_stmt_list()         ## nodelist
            else_node = nil
            if token() == :elsif
                else_node = parse_stmt_if()       ## stmtnode
            else
                if token() == :else
                    scan()
                    else_node = parse_stmt_list()  ## nodelist
                end
                _syntaxerr("':else' is not closed by ':end'.") unless token() == :end
                scan()
            end
            return IfStmtNode.new(:if, then_node, else_node, cond_expr)
        end


        ##
        ## * BNF:
        ##    while-stmt ::= ':while' '(' assignment ')' stmt-list ':end'
        ##
        ## * return node:
        ##   token::     :while
        ##   left::      NodeList
        ##   right::     nil
        ##   condition::  expression ExprNode
        ##
        def parse_stmt_while
            Kwartz::assert() unless token() == :while
            scan()
            _syntaxerr("':while' requires '('.") unless token() == '('
            scan()
            cond_expr = parse_assignment()
            _syntaxerr("':while(' is not closed.") unless token() == ')'
            scan()
            nodelist = parse_stmt_list()
            _syntaxerr("':while' is not closed by ':end'.") unless token() == :end
            scan()
            return WhileStmtNode.new(:while, nodelist, nil, cond_expr)
        end


        ##
        ## * BNF:
        ##    foreach-stmt ::= ':foreach' '(' expression '=' expression ')'
        ##                    stmt-list ':end'
        ##
        ## * return node:
        ##   token::  :foreach
        ##   left::   assignment ExprNode
        ##   right::  NodeList
        ##
        def parse_stmt_foreach
            Kwartz::assert() unless token() == :foreach
            scan()
            _syntaxerr("':foreach' requires '('.") unless token() == '('
            scan()
            assign_expr = parse_assignment(true)
            _syntaxerr("':foreach(' is not closed.") unless token() == ')'
            scan()
            _syntaxerr("':foreach' requires assignment.") unless assign_expr.token == '='
            nodelist = parse_stmt_list()
            _syntaxerr("':foreach' is not closed by ':end'.") unless token() == :end
            scan()
            return ForeachStmtNode.new(:foreach, assign_expr, nodelist)
        end


        ##
        ## * BNF:
        ##    print-stmt ::= ':print'  '(' expression { ',' expression } ')'
        ##
        ## * return node:
        ##   token::  :print
        ##   left::   expression ExprNode
        ##   right::  nil
        ##
        def parse_stmt_print
            Kwartz::assert() unless token() == :print
            scan()
            _syntaxerr("':print' requires '('.") unless token() == '('
            scan()
            arg_expr = parse_expression()
            while token() == ',' do
                scan()
                arg_expr2 = parse_expression()
                arg_expr  = ExprNode.new(',', arg_expr, arg_expr2)
            end
            _syntaxerr("':print(' is not closed.") unless token() == ')'
            scan()
            return PrintStmtNode.new(:print, arg_expr, nil)
        end


        ##
        ## * BNF:
        ##    macro-stmt ::= ':macro' '(' name ')' stmt-list ':end'
        ##
        ## * return node:
        ##   token::  :macro
        ##   left::   name String
        ##   right::  NodeList
        ##
        def parse_stmt_macro
            Kwartz::assert() unless token() == :macro || token() == :elem
            scan()
            _syntaxerr("':macro' requires '('.") unless token() == '('
            scan()
            name_expr = parse_expression()
            _syntaxerr("':macro(' is not closed.") unless token() == ')'
            scan()
            _syntaxerr("':macro' requires a name.") unless name_expr.token == :variable
            name = name_expr.left
            nodelist = parse_stmt_list()
            _syntaxerr("':macro' is not closed by ':end'.") unless token() == :end
            scan()
            return MacroStmtNode.new(:macro, name, nodelist)
        end


        ##
        ## * BNF:
        ##    elem-stmt  ::= ':elem'  '(' name ')' stmt-list ':end'
        ##
        ## * return node:
        ##   token::  :macro
        ##   left::   name String
        ##   right::  NodeList
        ##
        def parse_stmt_elem
            Kwartz::assert() unless token() == :elem
            scan()
            _syntaxerr("':elem' requires '('.") unless token() == '('
            scan()
            name_expr = parse_expression()
            _syntaxerr("':elem(' is not closed.") unless token() == ')'
            scan()
            _syntaxerr("':elem' requires an element name.") unless name_expr.token == :variable
            name = name_expr.left
            _push_element_name(name)
            nodelist = parse_stmt_list()
            _syntaxerr("':elem' is not closed by ':end'.") unless token() == :end
            _pop_element_name()
            scan()
            return MacroStmtNode.new(:macro, 'elem_' + name, nodelist)
        end


        ##
        ## * BNF:
        ##    expand-stmt ::= ':expand' '(' name ')'
        ##
        ## * return node:
        ##   token::  :expand
        ##   left::   name String
        ##   right::  nil
        ##
        def parse_stmt_expand
            Kwartz::assert() unless token() == :expand
            scan()
            _syntaxerr("':expand' requires '('.") unless token() == '('
            scan()
            name_expr = parse_expression()
            _syntaxerr("':expand(' is not closed.") unless token() == ')'
            scan()
            _syntaxerr("':macro' requires a name.") unless name_expr.token == :variable
            name = name_expr.left
            return ExpandStmtNode.new(:expand, name, nil)
        end


        ##
        ## * BNF:
        ##     expand2-stmt ::= '@' macro-name
        ##
        ## * return node:
        ##   token::   :expand
        ##   left::    name String
        ##   right::   nil
        ##
        def parse_stmt_expand2
            Kwartz::assert() unless token() == :expand2
            macro_name = token_str()
            scan()
            return ExpandStmtNode.new(:expand, macro_name, nil)
        end


        ##
        ## * BNF:
        ##     special-expand-stmt ::= '@stag' | '@cont' | '@etag' | ':stag' | ':cont' | ':etag'
        ##
        ## * return node:
        ##   token::   :expand
        ##   left::    name String
        ##   right::   nil
        ##
        def parse_stmt_specialexpand
            Kwartz::assert() unless token() == :stag || token() == :cont || token() == :etag
            elem_name = _element_name()
            unless elem_name
                msg = "@stag, @cont or @etag must be in :elem() statement."
                raise SemanticError.new(msg)
            end
            macro_name = "#{token_str()}_#{elem_name}"
            scan()
            return ExpandStmtNode.new(:expand, macro_name, nil)
        end


        ##
        ## * BNF:
        ##     value-stmt ::= ':value' '(' name '=' expression ')'
        ##
        ## * return node:
        ##   token::   :value
        ##   left::    name String ('cont_' + name)
        ##   right::   NodeList (of PrintStmtNode)
        ##
        def parse_stmt_value
            Kwartz::assert() unless token() == :value
            scan()
            _syntaxerr("':value' requires '('.") unless token() == '('
            scan()
            assign_expr = parse_assignment()
            _syntaxerr("':value(' is not closed.") unless token() == ')'
            scan()
            _syntaxerr("':value' requires assignment.") unless assign_expr.token == '='
            name_expr = assign_expr.left
            _syntaxerr("':value' requires a name.") unless name_expr.token == :variable
            name = name_expr.left
            expr = assign_expr.right
            print_stmt = PrintStmtNode.new(:print, expr, nil)
            nodelist = NodeList.new([print_stmt])
            return  MacroStmtNode.new(:macro, 'cont_' + name, nodelist)
        end


        ##
        ## * BNF:
        ##    rawcode ::= ':::' raw-string | ':rawcode' '(' string ')'
        ##
        ## * return node:
        ##   token::  :rawcode
        ##   left::   rawcode String
        ##   right::  nil
        ##
        def parse_stmt_rawcode
            t = token()
            if t == ':::'
                str = token_str()
            elsif t == :rawcode
                scan()
                _syntaxerr("':rawcode' needs '('.") unless token() == '('
                scan()
                expr = parse_expression()
                _syntaxerr("':rawcode(' is not closed.") unless token() == ')'
                _syntaxerr("':rawcode()' needs a string.") unless expr.token == :string
                str = expr.left
            end
            scan()
            return RawcodeStmtNode.new(:rawcode, str, nil)
        end


        ##
        ## * BNF:
        ##    load-stmt ::= ':load' '(' string ')'
        ##
        ## * return:  nodelist
        ##
        def parse_stmt_load
            Kwartz::assert() unless token() == :load
            scan()
            _syntaxerr("':load' requires '('.") unless token() == '('
            scan()
            filename_expr = parse_expression()
            _syntaxerr("':load(' is not closed.") unless token() == ')'
            scan()
            _syntaxerr("':load' requires filename as a string.") unless filename_expr.token == :string
            filename = filename_expr.left
            @toppings[:load_path].each do |dir|
                if test(?d, dir) && test(?f, "#{dir}/#{filename}")
                    filename = "#{dir}/#{filename}"
                    break
                end
            end if @toppings[:load_path]
            unless test(?f, filename)
                msg = "'#{filename}': not found."
                raise ParseError.new(msg)
            end
            plcode = File.open(filename) { |f| f.read }
            nodelist = Kwartz::Helper.parse(plcode, @toppings)
            return nodelist
        end

        ##
        ## main parse method
        ##
        def parse
            nodelist = parse_stmt_list()
            unless token() == nil
                if token.is_a?(String)
                    s = "'#{token()}'"
                else
                    case token()
                    when :name, :number
                        s = "'#{token_str()}'"
                    when :string
                        s = "\"'#{token_str()}'\""
                    else
                        s = token()
                    end
                end
                _syntaxerr("#{s}: invalid statement.")
            end
            #
            macro_list = []
            stmt_list = []
            nodelist.each do |stmtnode|
                if stmtnode.token == :macro
                    macro_list << stmtnode
                else
                    stmt_list << stmtnode
                end
            end
            return NodeList.new(macro_list + stmt_list)
        end

    end