def dump_one_parser(parser_name, parser_id, p4_start_state, keep_pragmas=False):
    parser_dict = OrderedDict()
    parser_dict["name"] = parser_name
    parser_dict["id"] = parser_id
    parser_dict["init_state"] = p4_start_state.name
    parse_states = []

    accessible_parse_states = set()
    accessible_parse_states_ordered = []

    def find_accessible_parse_states(parse_state):
        if parse_state in accessible_parse_states:
            return
        accessible_parse_states.add(parse_state)
        accessible_parse_states_ordered.append(parse_state)
        for _, next_state in parse_state.branch_to.items():
            if isinstance(next_state, p4.p4_parse_state):
                find_accessible_parse_states(next_state)

    find_accessible_parse_states(p4_start_state)

    for p4_parse_state in accessible_parse_states_ordered:
        parse_state_dict = OrderedDict()
        parse_state_dict["name"] = p4_parse_state.name
        parse_state_dict["id"] = dump_one_parser.parse_state_id
        dump_one_parser.parse_state_id += 1

        parser_ops = []
        for parser_op in p4_parse_state.call_sequence:
            parser_op_dict = OrderedDict()
            op_type = parser_op[0]
            parameters = []
            if op_type == p4.parse_call.extract:
                parser_op_dict["op"] = "extract"
                header = parser_op[1]
                param_dict = OrderedDict()
                if header.virtual:
                    param_dict["type"] = "stack"
                    param_dict["value"] = header.base_name
                else:
                    param_dict["type"] = "regular"
                    param_dict["value"] = header.name
                parameters.append(param_dict)
            elif op_type == p4.parse_call.set:
                parser_op_dict["op"] = "set"
                dest_field, src = parser_op[1], parser_op[2]
                assert(type(dest_field) is p4.p4_field and
                       "parser assignment target should be a field")
                dest_dict = OrderedDict()
                src_dict = OrderedDict()
                dest_dict["type"] = "field"
                dest_dict["value"] = format_field_ref(dest_field)
                parameters.append(dest_dict)
                if type(src) is int or type(src) is long:
                    src_dict["type"] = "hexstr"
                    src_dict["value"] = format_hexstr(src)
                elif type(src) is p4.p4_field:
                    src_dict = format_field_ref_expression(src, False)
                elif type(src) is tuple:
                    src_dict["type"] = "lookahead"
                    src_dict["value"] = list(src)
                elif type(src) is p4.p4_expression:
                    src_dict["type"] = "expression"
                    src_dict["value"] = dump_expression(src)
                else:  # pragma: no cover
                    LOG_CRITICAL("invalid src type for set_metadata: %s",
                                 type(src))
                parameters.append(src_dict)
            else:  # pragma: no cover
                LOG_CRITICAL("invalid parser operation: %s", op_type)

            parser_op_dict["parameters"] = parameters
            parser_ops.append(parser_op_dict)

        parse_state_dict["parser_ops"] = parser_ops

        transition_key = []
        field_widths = []
        for switch_ref in p4_parse_state.branch_on:
            switch_ref_dict = OrderedDict()
            if type(switch_ref) is p4.p4_field:
                field_widths.append(switch_ref.width)
                header = switch_ref.instance
                if header.virtual:
                    switch_ref_dict["type"] = "stack_field"
                else:
                    switch_ref_dict["type"] = "field"
                switch_ref_dict["value"] = format_field_ref(switch_ref)
            elif type(switch_ref) is tuple:
                field_widths.append(switch_ref[1])
                switch_ref_dict["type"] = "lookahead"
                switch_ref_dict["value"] = list(switch_ref)
            else:  # pragma: no cover
                LOG_CRITICAL("not supported")
            transition_key.append(switch_ref_dict)
        parse_state_dict["transition_key"] = transition_key

        transitions = []
        for branch_case, next_state in p4_parse_state.branch_to.items():
            transition_dict = OrderedDict()
            value, mask, type_ = None, None, None
            if branch_case == p4.P4_DEFAULT:
                type_ = "default"
            elif type(branch_case) is int:
                type_ = "hexstr"
                value = build_match_value(field_widths, branch_case)
            elif type(branch_case) is tuple:
                type_ = "hexstr"
                value, mask = (build_match_value(field_widths, branch_case[0]),
                               build_match_value(field_widths, branch_case[1]))
            elif type(branch_case) is p4.p4_parse_value_set:
                type_ = "parse_vset"
                value = branch_case.name
                # mask not supported yet in compiler, even though it is
                # supported in bmv2
                mask = None
                vset_bits = sum(field_widths)
                if value in dump_parsers.vset_widths:
                    curr_bits = dump_parsers.vset_widths[value]
                    if curr_bits != vset_bits:  # pragma: no cover
                        LOG_CRITICAL("when parser value set used multiple "
                                     "times, widths cannot clash")
                else:
                    dump_parsers.vset_widths[value] = vset_bits
            else:  # pragma: no cover
                LOG_CRITICAL("invalid parser branching")

            transition_dict["type"] = type_
            transition_dict["value"] = value
            transition_dict["mask"] = mask

            if isinstance(next_state, p4.p4_parse_state):
                transition_dict["next_state"] = next_state.name
            else:
                # we do not support control flows here anymore
                transition_dict["next_state"] = None

            transitions.append(transition_dict)

        parse_state_dict["transitions"] = transitions

        if keep_pragmas:
            add_pragmas(parse_state_dict, p4_parse_state)

        parse_states.append(parse_state_dict)

    parser_dict["parse_states"] = parse_states

    return parser_dict