diff options
Diffstat (limited to 'circuitpython/ports/raspberrypi/sdk/tools')
26 files changed, 11507 insertions, 0 deletions
diff --git a/circuitpython/ports/raspberrypi/sdk/tools/CMakeLists.txt b/circuitpython/ports/raspberrypi/sdk/tools/CMakeLists.txt new file mode 100644 index 0000000..f66f9d0 --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/CMakeLists.txt @@ -0,0 +1,46 @@ +function(_pico_init_pioasm) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PICO_SDK_PATH}/tools) + # todo CMAKE_CURRENT_FUNCTION_LIST_DIR ... what version? + find_package(Pioasm REQUIRED) +endfunction() + +function(pico_generate_pio_header TARGET PIO) + _pico_init_pioasm() + cmake_parse_arguments(pico_generate_pio_header "" "OUTPUT_DIR" "" ${ARGN} ) + + if (pico_generate_pio_header_OUTPUT_DIR) + get_filename_component(HEADER_DIR ${pico_generate_pio_header_OUTPUT_DIR} ABSOLUTE) + else() + set(HEADER_DIR "${CMAKE_CURRENT_BINARY_DIR}") + endif() + get_filename_component(PIO_NAME ${PIO} NAME) + set(HEADER "${HEADER_DIR}/${PIO_NAME}.h") + #message("Will generate ${HEADER}") + get_filename_component(HEADER_GEN_TARGET ${PIO} NAME_WE) + set(HEADER_GEN_TARGET "${TARGET}_${HEADER_GEN_TARGET}_pio_h") + + add_custom_target(${HEADER_GEN_TARGET} DEPENDS ${HEADER}) + + add_custom_command(OUTPUT ${HEADER} + DEPENDS ${PIO} + COMMAND Pioasm -o c-sdk ${PIO} ${HEADER} + ) + add_dependencies(${TARGET} ${HEADER_GEN_TARGET}) + get_target_property(target_type ${TARGET} TYPE) + if ("INTERFACE_LIBRARY" STREQUAL "${target_type}") + target_include_directories(${TARGET} INTERFACE ${HEADER_DIR}) + else() + target_include_directories(${TARGET} PUBLIC ${HEADER_DIR}) + endif() +endfunction() + +function(pico_add_uf2_output TARGET) + if (NOT ELF2UF2_FOUND) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PICO_SDK_PATH}/tools) + find_package(ELF2UF2) + endif() + if (ELF2UF2_FOUND) + add_custom_command(TARGET ${TARGET} POST_BUILD + COMMAND ELF2UF2 $<TARGET_FILE:${TARGET}> $<IF:$<BOOL:$<TARGET_PROPERTY:${TARGET},OUTPUT_NAME>>,$<TARGET_PROPERTY:${TARGET},OUTPUT_NAME>,$<TARGET_PROPERTY:${TARGET},NAME>>.uf2) + endif() +endfunction() diff --git a/circuitpython/ports/raspberrypi/sdk/tools/FindELF2UF2.cmake b/circuitpython/ports/raspberrypi/sdk/tools/FindELF2UF2.cmake new file mode 100644 index 0000000..fb5dd97 --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/FindELF2UF2.cmake @@ -0,0 +1,43 @@ +# Finds (or builds) the ELF2UF2 executable +# +# This will define the following variables +# +# ELF2UF2_FOUND +# +# and the following imported targets +# +# ELF2UF2 +# + +if (NOT ELF2UF2_FOUND) + # todo we would like to use pckgconfig to look for it first + # see https://pabloariasal.github.io/2018/02/19/its-time-to-do-cmake-right/ + + include(ExternalProject) + + set(ELF2UF2_SOURCE_DIR ${PICO_SDK_PATH}/tools/elf2uf2) + set(ELF2UF2_BINARY_DIR ${CMAKE_BINARY_DIR}/elf2uf2) + + set(ELF2UF2_BUILD_TARGET ELF2UF2Build) + set(ELF2UF2_TARGET ELF2UF2) + + if (NOT TARGET ${ELF2UF2_BUILD_TARGET}) + pico_message_debug("ELF2UF2 will need to be built") + ExternalProject_Add(${ELF2UF2_BUILD_TARGET} + PREFIX elf2uf2 SOURCE_DIR ${ELF2UF2_SOURCE_DIR} + BINARY_DIR ${ELF2UF2_BINARY_DIR} + BUILD_ALWAYS 1 # force dependency checking + INSTALL_COMMAND "" + ) + endif() + + set(ELF2UF2_EXECUTABLE ${ELF2UF2_BINARY_DIR}/elf2uf2) + if(NOT TARGET ${ELF2UF2_TARGET}) + add_executable(${ELF2UF2_TARGET} IMPORTED) + endif() + set_property(TARGET ${ELF2UF2_TARGET} PROPERTY IMPORTED_LOCATION + ${ELF2UF2_EXECUTABLE}) + + add_dependencies(${ELF2UF2_TARGET} ${ELF2UF2_BUILD_TARGET}) + set(ELF2UF2_FOUND 1) +endif() diff --git a/circuitpython/ports/raspberrypi/sdk/tools/FindPioasm.cmake b/circuitpython/ports/raspberrypi/sdk/tools/FindPioasm.cmake new file mode 100644 index 0000000..91b9021 --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/FindPioasm.cmake @@ -0,0 +1,50 @@ +# Finds (or builds) the Pioasm executable +# +# This will define the following variables +# +# Pioasm_FOUND +# +# and the following imported targets +# +# Pioasm +# + +if (NOT Pioasm_FOUND) + # todo we would like to use pckgconfig to look for it first + # see https://pabloariasal.github.io/2018/02/19/its-time-to-do-cmake-right/ + + include(ExternalProject) + + set(PIOASM_SOURCE_DIR ${PICO_SDK_PATH}/tools/pioasm) + set(PIOASM_BINARY_DIR ${CMAKE_BINARY_DIR}/pioasm) + + set(PioasmBuild_TARGET PioasmBuild) + set(Pioasm_TARGET Pioasm) + + if (NOT TARGET ${PioasmBuild_TARGET}) + pico_message_debug("PIOASM will need to be built") +# message("Adding external project ${PioasmBuild_Target} in ${CMAKE_CURRENT_LIST_DIR}}") + ExternalProject_Add(${PioasmBuild_TARGET} + PREFIX pioasm SOURCE_DIR ${PIOASM_SOURCE_DIR} + BINARY_DIR ${PIOASM_BINARY_DIR} + BUILD_ALWAYS 1 # force dependency checking + INSTALL_COMMAND "" + ) + endif() + + if (CMAKE_HOST_WIN32) + set(Pioasm_EXECUTABLE ${PIOASM_BINARY_DIR}/pioasm.exe) + else() + set(Pioasm_EXECUTABLE ${PIOASM_BINARY_DIR}/pioasm) + endif() + if(NOT TARGET ${Pioasm_TARGET}) +# message("Adding executable ${Pioasm_Target} in ${CMAKE_CURRENT_LIST_DIR}") + add_executable(${Pioasm_TARGET} IMPORTED) + endif() + set_property(TARGET ${Pioasm_TARGET} PROPERTY IMPORTED_LOCATION + ${Pioasm_EXECUTABLE}) + +# message("EXE is ${Pioasm_EXECUTABLE}") + add_dependencies(${Pioasm_TARGET} ${PioasmBuild_TARGET}) + set(Pioasm_FOUND 1) +endif() diff --git a/circuitpython/ports/raspberrypi/sdk/tools/check_doxygen_groups.py b/circuitpython/ports/raspberrypi/sdk/tools/check_doxygen_groups.py new file mode 100755 index 0000000..bbcd9f5 --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/check_doxygen_groups.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2021 Raspberry Pi (Trading) Ltd. +# +# SPDX-License-Identifier: BSD-3-Clause +# +# +# Little script to check that every \ingroup has a matching \defgroup +# +# Usage: +# +# Run from the root of the tree to check + + +import subprocess +import re +import sys +import os + +groups = {} +any_errors = False + +res = subprocess.run(['git', 'grep', '\\defgroup'], check=True, stdout=subprocess.PIPE) +for line in res.stdout.decode('utf8').split('\n'): + m = re.match(r'^(\S+):.*\\defgroup\s+(\w+)', line) + if m: + filename = m.group(1) + group = m.group(2) + if os.path.basename(filename) in ('check_doxygen_groups.py', 'index.h'): + continue + if group in groups: + any_errors = True + print("{} uses \\defgroup {} but so does {}".format(groups[group], group, filename)) + else: + groups[group] = filename + +res = subprocess.run(['git', 'grep', '\\ingroup'], check=True, stdout=subprocess.PIPE) +for line in res.stdout.decode('utf8').split('\n'): + m = re.match(r'^(\S+):.*\\ingroup\s+(\w+)', line) + if m: + filename = m.group(1) + group = m.group(2) + if os.path.basename(filename) in ('check_doxygen_groups.py', 'index.h'): + continue + if group not in groups: + any_errors = True + print("{} uses \\ingroup {} which was never defined".format(filename, group)) + +sys.exit(any_errors) diff --git a/circuitpython/ports/raspberrypi/sdk/tools/elf2uf2/CMakeLists.txt b/circuitpython/ports/raspberrypi/sdk/tools/elf2uf2/CMakeLists.txt new file mode 100644 index 0000000..070e114 --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/elf2uf2/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.12) +project(elf2uf2) + +set(CMAKE_CXX_STANDARD 14) + +add_subdirectory(../../src/common/boot_uf2 boot_uf2_headers) + +add_executable(elf2uf2 main.cpp) +target_link_libraries(elf2uf2 boot_uf2_headers)
\ No newline at end of file diff --git a/circuitpython/ports/raspberrypi/sdk/tools/elf2uf2/elf.h b/circuitpython/ports/raspberrypi/sdk/tools/elf2uf2/elf.h new file mode 100644 index 0000000..32e3dbb --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/elf2uf2/elf.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _ELF_H +#define _ELF_H + +#include <stdint.h> + +#define ELF_MAGIC 0x464c457fu + +#define EM_ARM 0x28u + +#define EF_ARM_ABI_FLOAT_HARD 0x00000400u + +#define PT_LOAD 0x00000001u + +#pragma pack(push, 1) +struct elf_header { + uint32_t magic; + uint8_t arch_class; + uint8_t endianness; + uint8_t version; + uint8_t abi; + uint8_t abi_version; + uint8_t _pad[7]; + uint16_t type; + uint16_t machine; + uint32_t version2; +}; + +struct elf32_header { + struct elf_header common; + uint32_t entry; + uint32_t ph_offset; + uint32_t sh_offset; + uint32_t flags; + uint16_t eh_size; + uint16_t ph_entry_size; + uint16_t ph_num; + uint16_t sh_entry_size; + uint16_t sh_num; + uint16_t sh_str_index; +}; + +struct elf32_ph_entry { + uint32_t type; + uint32_t offset; + uint32_t vaddr; + uint32_t paddr; + uint32_t filez; + uint32_t memsz; + uint32_t flags; + uint32_t align; +}; +#pragma pack(pop) + +#endif
\ No newline at end of file diff --git a/circuitpython/ports/raspberrypi/sdk/tools/elf2uf2/main.cpp b/circuitpython/ports/raspberrypi/sdk/tools/elf2uf2/main.cpp new file mode 100644 index 0000000..2c0ddcd --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/elf2uf2/main.cpp @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <cstdio> +#include <map> +#include <vector> +#include <cstring> +#include <cstdarg> +#include <algorithm> +#include "boot/uf2.h" +#include "elf.h" + +typedef unsigned int uint; + +#define ERROR_ARGS -1 +#define ERROR_FORMAT -2 +#define ERROR_INCOMPATIBLE -3 +#define ERROR_READ_FAILED -4 +#define ERROR_WRITE_FAILED -5 + +static char error_msg[512]; +static bool verbose; + +static int fail(int code, const char *format, ...) { + va_list args; + va_start(args, format); + vsnprintf(error_msg, sizeof(error_msg), format, args); + va_end(args); + return code; +} + +static int fail_read_error() { + return fail(ERROR_READ_FAILED, "Failed to read input file"); +} + +static int fail_write_error() { + return fail(ERROR_WRITE_FAILED, "Failed to write output file"); +} + +// we require 256 (as this is the page size supported by the device) +#define LOG2_PAGE_SIZE 8u +#define PAGE_SIZE (1u << LOG2_PAGE_SIZE) + +struct address_range { + enum type { + CONTENTS, // may have contents + NO_CONTENTS, // must be uninitialized + IGNORE // will be ignored + }; + address_range(uint32_t from, uint32_t to, type type) : from(from), to(to), type(type) {} + address_range() : address_range(0, 0, IGNORE) {} + type type; + uint32_t to; + uint32_t from; +}; + +typedef std::vector<address_range> address_ranges; + +#define MAIN_RAM_START 0x20000000u +#define MAIN_RAM_END 0x20042000u +#define FLASH_START 0x10000000u +#define FLASH_END 0x15000000u +#define XIP_SRAM_START 0x15000000u +#define XIP_SRAM_END 0x15004000u +#define MAIN_RAM_BANKED_START 0x21000000u +#define MAIN_RAM_BANKED_END 0x21040000u + +const address_ranges rp2040_address_ranges_flash { + address_range(FLASH_START, FLASH_END, address_range::type::CONTENTS), + address_range(MAIN_RAM_START, MAIN_RAM_END, address_range::type::NO_CONTENTS), + address_range(MAIN_RAM_BANKED_START, MAIN_RAM_BANKED_END, address_range::type::NO_CONTENTS) +}; + +const address_ranges rp2040_address_ranges_ram { + address_range(MAIN_RAM_START, MAIN_RAM_END, address_range::type::CONTENTS), + address_range(XIP_SRAM_START, XIP_SRAM_END, address_range::type::CONTENTS), + address_range(0x00000000u, 0x00004000u, address_range::type::IGNORE) // for now we ignore the bootrom if present +}; + +struct page_fragment { + page_fragment(uint32_t file_offset, uint32_t page_offset, uint32_t bytes) : file_offset(file_offset), page_offset(page_offset), bytes(bytes) {} + uint32_t file_offset; + uint32_t page_offset; + uint32_t bytes; +}; + +static int usage() { + fprintf(stderr, "Usage: elf2uf2 (-v) <input ELF file> <output UF2 file>\n"); + return ERROR_ARGS; +} + +static int read_and_check_elf32_header(FILE *in, elf32_header& eh_out) { + if (1 != fread(&eh_out, sizeof(eh_out), 1, in)) { + return fail(ERROR_READ_FAILED, "Unable to read ELF header"); + } + if (eh_out.common.magic != ELF_MAGIC) { + return fail(ERROR_FORMAT, "Not an ELF file"); + } + if (eh_out.common.version != 1 || eh_out.common.version2 != 1) { + return fail(ERROR_FORMAT, "Unrecognized ELF version"); + } + if (eh_out.common.arch_class != 1 || eh_out.common.endianness != 1) { + return fail(ERROR_INCOMPATIBLE, "Require 32 bit little-endian ELF"); + } + if (eh_out.eh_size != sizeof(struct elf32_header)) { + return fail(ERROR_FORMAT, "Invalid ELF32 format"); + } + if (eh_out.common.machine != EM_ARM) { + return fail(ERROR_FORMAT, "Not an ARM executable"); + } + if (eh_out.common.abi != 0) { + return fail(ERROR_INCOMPATIBLE, "Unrecognized ABI"); + } + if (eh_out.flags & EF_ARM_ABI_FLOAT_HARD) { + return fail(ERROR_INCOMPATIBLE, "HARD-FLOAT not supported"); + } + return 0; +} + +int check_address_range(const address_ranges& valid_ranges, uint32_t addr, uint32_t vaddr, uint32_t size, bool uninitialized, address_range &ar) { + for(const auto& range : valid_ranges) { + if (range.from <= addr && range.to >= addr + size) { + if (range.type == address_range::type::NO_CONTENTS && !uninitialized) { + return fail(ERROR_INCOMPATIBLE, "ELF contains memory contents for uninitialized memory"); + } + ar = range; + if (verbose) { + printf("%s segment %08x->%08x (%08x->%08x)\n", uninitialized ? "Uninitialized" : "Mapped", addr, + addr + size, vaddr, vaddr+size); + } + return 0; + } + } + return fail(ERROR_INCOMPATIBLE, "Memory segment %08x->%08x is outside of valid address range for device", addr, addr+size); +} + +int read_and_check_elf32_ph_entries(FILE *in, const elf32_header &eh, const address_ranges& valid_ranges, std::map<uint32_t, std::vector<page_fragment>>& pages) { + if (eh.ph_entry_size != sizeof(elf32_ph_entry)) { + return fail(ERROR_FORMAT, "Invalid ELF32 program header"); + } + if (eh.ph_num) { + std::vector<elf32_ph_entry> entries(eh.ph_num); + if (fseek(in, eh.ph_offset, SEEK_SET)) { + return fail_read_error(); + } + if (eh.ph_num != fread(&entries[0], sizeof(struct elf32_ph_entry), eh.ph_num, in)) { + return fail_read_error(); + } + for(uint i=0;i<eh.ph_num;i++) { + elf32_ph_entry& entry = entries[i]; + if (entry.type == PT_LOAD && entry.memsz) { + address_range ar; + int rc; + uint mapped_size = std::min(entry.filez, entry.memsz); + if (mapped_size) { + rc = check_address_range(valid_ranges, entry.paddr, entry.vaddr, mapped_size, false, ar); + if (rc) return rc; + // we don't download uninitialized, generally it is BSS and should be zero-ed by crt0.S, or it may be COPY areas which are undefined + if (ar.type != address_range::type::CONTENTS) { + if (verbose) printf(" ignored\n"); + continue; + } + uint addr = entry.paddr; + uint remaining = mapped_size; + uint file_offset = entry.offset; + while (remaining) { + uint off = addr & (PAGE_SIZE - 1); + uint len = std::min(remaining, PAGE_SIZE - off); + auto &fragments = pages[addr - off]; // list of fragments + // note if filesz is zero, we want zero init which is handled because the + // statement above creates an empty page fragment list + // check overlap with any existing fragments + for (const auto &fragment : fragments) { + if ((off < fragment.page_offset + fragment.bytes) != + ((off + len) <= fragment.page_offset)) { + fail(ERROR_FORMAT, "In memory segments overlap"); + } + } + fragments.push_back( + page_fragment{file_offset,off,len}); + addr += len; + file_offset += len; + remaining -= len; + } + } + if (entry.memsz > entry.filez) { + // we have some uninitialized data too + rc = check_address_range(valid_ranges, entry.paddr + entry.filez, entry.vaddr + entry.filez, entry.memsz - entry.filez, true, + ar); + if (rc) return rc; + } + } + } + } + return 0; +} + +int realize_page(FILE *in, const std::vector<page_fragment> &fragments, uint8_t *buf, uint buf_len) { + assert(buf_len >= PAGE_SIZE); + for(auto& frag : fragments) { + assert(frag.page_offset >= 0 && frag.page_offset < PAGE_SIZE && frag.page_offset + frag.bytes <= PAGE_SIZE); + if (fseek(in, frag.file_offset, SEEK_SET)) { + return fail_read_error(); + } + if (1 != fread(buf + frag.page_offset, frag.bytes, 1, in)) { + return fail_read_error(); + } + } + return 0; +} + +static bool is_address_valid(const address_ranges& valid_ranges, uint32_t addr) { + for(const auto& range : valid_ranges) { + if (range.from <= addr && range.to > addr) { + return true; + } + } + return false; +} + +static bool is_address_initialized(const address_ranges& valid_ranges, uint32_t addr) { + for(const auto& range : valid_ranges) { + if (range.from <= addr && range.to > addr) { + return address_range::type::CONTENTS == range.type; + } + } + return false; +} + +static bool is_address_mapped(const std::map<uint32_t, std::vector<page_fragment>>& pages, uint32_t addr) { + uint32_t page = addr & ~(PAGE_SIZE - 1); + if (!pages.count(page)) return false; + // todo check actual address within page + return true; +} + +int elf2uf2(FILE *in, FILE *out) { + elf32_header eh; + std::map<uint32_t, std::vector<page_fragment>> pages; + int rc = read_and_check_elf32_header(in, eh); + bool ram_style = false; + address_ranges valid_ranges = {}; + if (!rc) { + ram_style = is_address_initialized(rp2040_address_ranges_ram, eh.entry); + if (verbose) { + if (ram_style) { + printf("Detected RAM binary\n"); + } else { + printf("Detected FLASH binary\n"); + } + } + valid_ranges = ram_style ? rp2040_address_ranges_ram : rp2040_address_ranges_flash; + rc = read_and_check_elf32_ph_entries(in, eh, valid_ranges, pages); + } + if (rc) return rc; + if (pages.empty()) { + return fail(ERROR_INCOMPATIBLE, "The input file has no memory pages"); + } + uint page_num = 0; + if (ram_style) { + uint32_t expected_ep_main_ram = UINT32_MAX; + uint32_t expected_ep_xip_sram = UINT32_MAX; + for(auto& page_entry : pages) { + if ( ((page_entry.first >= MAIN_RAM_START) && (page_entry.first < MAIN_RAM_END)) && (page_entry.first < expected_ep_main_ram) ) { + expected_ep_main_ram = page_entry.first | 0x1; + } else if ( ((page_entry.first >= XIP_SRAM_START) && (page_entry.first < XIP_SRAM_END)) && (page_entry.first < expected_ep_xip_sram) ) { + expected_ep_xip_sram = page_entry.first | 0x1; + } + } + uint32_t expected_ep = (UINT32_MAX != expected_ep_main_ram) ? expected_ep_main_ram : expected_ep_xip_sram; + if (eh.entry == expected_ep_xip_sram) { + return fail(ERROR_INCOMPATIBLE, "B0/B1 Boot ROM does not support direct entry into XIP_SRAM\n"); + } else if (eh.entry != expected_ep) { + return fail(ERROR_INCOMPATIBLE, "A RAM binary should have an entry point at the beginning: %08x (not %08x)\n", expected_ep, eh.entry); + } + static_assert(0 == (MAIN_RAM_START & (PAGE_SIZE - 1)), ""); + // currently don't require this as entry point is now at the start, we don't know where reset vector is +#if 0 + uint8_t buf[PAGE_SIZE]; + rc = realize_page(in, pages[MAIN_RAM_START], buf, sizeof(buf)); + if (rc) return rc; + uint32_t sp = ((uint32_t *)buf)[0]; + uint32_t ip = ((uint32_t *)buf)[1]; + if (!is_address_mapped(pages, ip)) { + return fail(ERROR_INCOMPATIBLE, "Vector table at %08x is invalid: reset vector %08x is not in mapped memory", + MAIN_RAM_START, ip); + } + if (!is_address_valid(valid_ranges, sp - 4)) { + return fail(ERROR_INCOMPATIBLE, "Vector table at %08x is invalid: stack pointer %08x is not in RAM", + MAIN_RAM_START, sp); + } +#endif + } + uf2_block block; + block.magic_start0 = UF2_MAGIC_START0; + block.magic_start1 = UF2_MAGIC_START1; + block.flags = UF2_FLAG_FAMILY_ID_PRESENT; + block.payload_size = PAGE_SIZE; + block.num_blocks = (uint32_t)pages.size(); + block.file_size = RP2040_FAMILY_ID; + block.magic_end = UF2_MAGIC_END; + for(auto& page_entry : pages) { + block.target_addr = page_entry.first; + block.block_no = page_num++; + if (verbose) { + printf("Page %d / %d %08x\n", block.block_no, block.num_blocks, block.target_addr); + } + memset(block.data, 0, sizeof(block.data)); + rc = realize_page(in, page_entry.second, block.data, sizeof(block.data)); + if (rc) return rc; + if (1 != fwrite(&block, sizeof(uf2_block), 1, out)) { + return fail_write_error(); + } + } + return 0; +} + +int main(int argc, char **argv) { + int arg = 1; + if (arg < argc && !strcmp(argv[arg], "-v")) { + verbose = true; + arg++; + } + if (argc < arg + 2) { + return usage(); + } + const char *in_filename = argv[arg++]; + FILE *in = fopen(in_filename, "rb"); + if (!in) { + fprintf(stderr, "Can't open input file '%s'\n", in_filename); + return ERROR_ARGS; + } + const char *out_filename = argv[arg++]; + FILE *out = fopen(out_filename, "wb"); + if (!out) { + fprintf(stderr, "Can't open output file '%s'\n", out_filename); + return ERROR_ARGS; + } + + int rc = elf2uf2(in, out); + fclose(in); + fclose(out); + if (rc) { + remove(out_filename); + if (error_msg[0]) { + fprintf(stderr, "ERROR: %s\n", error_msg); + } + } + return rc; +} diff --git a/circuitpython/ports/raspberrypi/sdk/tools/extract_configs.py b/circuitpython/ports/raspberrypi/sdk/tools/extract_configs.py new file mode 100755 index 0000000..e45ae7c --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/extract_configs.py @@ -0,0 +1,217 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2021 Raspberry Pi (Trading) Ltd. +# +# SPDX-License-Identifier: BSD-3-Clause +# +# +# Script to scan the Raspberry Pi Pico SDK tree searching for configuration items +# Outputs a tab separated file of the configuration item: +# name location description type advanced default depends enumvalues group max min +# +# Usage: +# +# ./extract_configs.py <root of source tree> [output file] +# +# If not specified, output file will be `pico_configs.tsv` + + +import os +import sys +import re +import csv +import logging + +logger = logging.getLogger(__name__) +logging.basicConfig(level=logging.INFO) + +scandir = sys.argv[1] +outfile = sys.argv[2] if len(sys.argv) > 2 else 'pico_configs.tsv' + +CONFIG_RE = re.compile(r'//\s+PICO_CONFIG:\s+(\w+),\s+([^,]+)(?:,\s+(.*))?$') +DEFINE_RE = re.compile(r'#define\s+(\w+)\s+(.+?)(\s*///.*)?$') + +all_configs = {} +all_attrs = set() +all_descriptions = {} +all_defines = {} + + + +def ValidateAttrs(config_attrs): + _type = config_attrs.get('type', 'int') + + # Validate attrs + if _type == 'int': + assert 'enumvalues' not in config_attrs + _min = _max = _default = None + if config_attrs.get('min', None) is not None: + value = config_attrs['min'] + m = re.match(r'^(\d+)e(\d+)$', value.lower()) + if m: + _min = int(m.group(1)) * 10**int(m.group(2)) + else: + _min = int(value, 0) + if config_attrs.get('max', None) is not None: + value = config_attrs['max'] + m = re.match(r'^(\d+)e(\d+)$', value.lower()) + if m: + _max = int(m.group(1)) * 10**int(m.group(2)) + else: + _max = int(value, 0) + if config_attrs.get('default', None) is not None: + if '/' not in config_attrs['default']: + try: + value = config_attrs['default'] + m = re.match(r'^(\d+)e(\d+)$', value.lower()) + if m: + _default = int(m.group(1)) * 10**int(m.group(2)) + else: + _default = int(value, 0) + except ValueError: + pass + if _min is not None and _max is not None: + if _min > _max: + raise Exception('{} at {}:{} has min {} > max {}'.format(config_name, file_path, linenum, config_attrs['min'], config_attrs['max'])) + if _min is not None and _default is not None: + if _min > _default: + raise Exception('{} at {}:{} has min {} > default {}'.format(config_name, file_path, linenum, config_attrs['min'], config_attrs['default'])) + if _default is not None and _max is not None: + if _default > _max: + raise Exception('{} at {}:{} has default {} > max {}'.format(config_name, file_path, linenum, config_attrs['default'], config_attrs['max'])) + elif _type == 'bool': + + assert 'min' not in config_attrs + assert 'max' not in config_attrs + assert 'enumvalues' not in config_attrs + + _default = config_attrs.get('default', None) + if _default is not None: + if '/' not in _default: + if (_default.lower() != '0') and (config_attrs['default'].lower() != '1') and ( _default not in all_configs): + logger.info('{} at {}:{} has non-integer default value "{}"'.format(config_name, file_path, linenum, config_attrs['default'])) + + elif _type == 'enum': + + assert 'min' not in config_attrs + assert 'max' not in config_attrs + assert 'enumvalues' in config_attrs + + _enumvalues = tuple(config_attrs['enumvalues'].split('|')) + _default = None + if config_attrs.get('default', None) is not None: + _default = config_attrs['default'] + if _default is not None: + if _default not in _enumvalues: + raise Exception('{} at {}:{} has default value {} which isn\'t in list of enumvalues {}'.format(config_name, file_path, linenum, config_attrs['default'], config_attrs['enumvalues'])) + else: + raise Exception("Found unknown PICO_CONFIG type {} at {}:{}".format(_type, file_path, linenum)) + + + + +# Scan all .c and .h files in the specific path, recursively. + +for dirpath, dirnames, filenames in os.walk(scandir): + for filename in filenames: + file_ext = os.path.splitext(filename)[1] + if file_ext in ('.c', '.h'): + file_path = os.path.join(dirpath, filename) + + with open(file_path, encoding="ISO-8859-1") as fh: + linenum = 0 + for line in fh.readlines(): + linenum += 1 + line = line.strip() + m = CONFIG_RE.match(line) + if m: + config_name = m.group(1) + config_description = m.group(2) + _attrs = m.group(3) + # allow commas to appear inside brackets by converting them to and from NULL chars + _attrs = re.sub(r'(\(.+\))', lambda m: m.group(1).replace(',', '\0'), _attrs) + + if '=' in config_description: + raise Exception("For {} at {}:{} the description was set to '{}' - has the description field been omitted?".format(config_name, file_path, linenum, config_description)) + if config_description in all_descriptions: + raise Exception("Found description {} at {}:{} but it was already used at {}:{}".format(config_description, file_path, linenum, os.path.join(scandir, all_descriptions[config_description]['filename']), all_descriptions[config_description]['line_number'])) + else: + all_descriptions[config_description] = {'config_name': config_name, 'filename': os.path.relpath(file_path, scandir), 'line_number': linenum} + + config_attrs = {} + prev = None + # Handle case where attr value contains a comma + for item in _attrs.split(','): + if "=" not in item: + assert(prev) + item = prev + "," + item + try: + k, v = (i.strip() for i in item.split('=')) + except ValueError: + raise Exception('{} at {}:{} has malformed value {}'.format(config_name, file_path, linenum, item)) + config_attrs[k] = v.replace('\0', ',') + all_attrs.add(k) + prev = item + #print(file_path, config_name, config_attrs) + + if 'group' not in config_attrs: + raise Exception('{} at {}:{} has no group attribute'.format(config_name, file_path, linenum)) + + #print(file_path, config_name, config_attrs) + if config_name in all_configs: + raise Exception("Found {} at {}:{} but it was already declared at {}:{}".format(config_name, file_path, linenum, os.path.join(scandir, all_configs[config_name]['filename']), all_configs[config_name]['line_number'])) + else: + all_configs[config_name] = {'attrs': config_attrs, 'filename': os.path.relpath(file_path, scandir), 'line_number': linenum, 'description': config_description} + else: + m = DEFINE_RE.match(line) + if m: + name = m.group(1) + value = m.group(2) + # discard any 'u' qualifier + m = re.match(r'^((0x)?\d+)u$', value.lower()) + if m: + value = m.group(1) + else: + # discard any '_u(X)' macro + m = re.match(r'^_u\(((0x)?\d+)\)$', value.lower()) + if m: + value = m.group(1) + if name not in all_defines: + all_defines[name] = dict() + if value not in all_defines[name]: + all_defines[name][value] = set() + all_defines[name][value] = (file_path, linenum) + +# Check for defines with missing PICO_CONFIG entries +resolved_defines = dict() +for d in all_defines: + if d not in all_configs and d.startswith("PICO_"): + logger.warning("Potential unmarked PICO define {}".format(d)) + # resolve "nested defines" - this allows e.g. USB_DPRAM_MAX to resolve to USB_DPRAM_SIZE which is set to 4096 (which then matches the relevant PICO_CONFIG entry) + for val in all_defines[d]: + if val in all_defines: + resolved_defines[d] = all_defines[val] + +for config_name in all_configs: + + ValidateAttrs(all_configs[config_name]['attrs']) + + # Check that default values match up + if 'default' in all_configs[config_name]['attrs']: + if config_name in all_defines: + if all_configs[config_name]['attrs']['default'] not in all_defines[config_name] and (config_name not in resolved_defines or all_configs[config_name]['attrs']['default'] not in resolved_defines[config_name]): + if '/' in all_configs[config_name]['attrs']['default'] or ' ' in all_configs[config_name]['attrs']['default']: + continue + # There _may_ be multiple matching defines, but arbitrarily display just one in the error message + first_define_value = list(all_defines[config_name].keys())[0] + raise Exception('Found {} at {}:{} with a default of {}, but #define says {} (at {}:{})'.format(config_name, os.path.join(scandir, all_configs[config_name]['filename']), all_configs[config_name]['line_number'], all_configs[config_name]['attrs']['default'], first_define_value, all_defines[config_name][first_define_value][0], all_defines[config_name][first_define_value][1])) + else: + raise Exception('Found {} at {}:{} with a default of {}, but no matching #define found'.format(config_name, os.path.join(scandir, all_configs[config_name]['filename']), all_configs[config_name]['line_number'], all_configs[config_name]['attrs']['default'])) + +with open(outfile, 'w', newline='') as csvfile: + fieldnames = ('name', 'location', 'description', 'type') + tuple(sorted(all_attrs - set(['type']))) + writer = csv.DictWriter(csvfile, fieldnames=fieldnames, extrasaction='ignore', dialect='excel-tab') + + writer.writeheader() + for config_name in sorted(all_configs): + writer.writerow({'name': config_name, 'location': '{}:{}'.format(all_configs[config_name]['filename'], all_configs[config_name]['line_number']), 'description': all_configs[config_name]['description'], **all_configs[config_name]['attrs']}) diff --git a/circuitpython/ports/raspberrypi/sdk/tools/pioasm/CMakeLists.txt b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/CMakeLists.txt new file mode 100644 index 0000000..df80530 --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/CMakeLists.txt @@ -0,0 +1,43 @@ +cmake_minimum_required(VERSION 3.4) +project(pioasm CXX) + +set(CMAKE_CXX_STANDARD 11) + +if (PIOASM_GENERATE_PARSER) + find_package(BISON 3.4.2) + find_package(FLEX 2.5.13) # no idea about the version + + FLEX_TARGET(pioasm_lexer lexer.ll ${CMAKE_CURRENT_SOURCE_DIR}/gen/lexer.cpp) + BISON_TARGET(pioasm_parser parser.yy ${CMAKE_CURRENT_SOURCE_DIR}/gen/parser.cpp COMPILE_FLAGS "-Wcounterexamples") + ADD_FLEX_BISON_DEPENDENCY(pioasm_lexer pioasm_parser) +endif() + +add_executable(pioasm + main.cpp + pio_assembler.cpp + pio_disassembler.cpp + gen/lexer.cpp + gen/parser.cpp +) + +target_sources(pioasm PRIVATE c_sdk_output.cpp) +target_sources(pioasm PRIVATE python_output.cpp) +target_sources(pioasm PRIVATE hex_output.cpp) +target_sources(pioasm PRIVATE ada_output.cpp) +target_sources(pioasm PRIVATE ${PIOASM_EXTRA_SOURCE_FILES}) + +if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND + (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "7") AND + (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9") AND + (CMAKE_SYSTEM_PROCESSOR MATCHES "^arm.*$")) + # disable GCC ARM info notice about ABI change + target_compile_options(pioasm PRIVATE -Wno-psabi) +endif() + +target_include_directories(pioasm PRIVATE ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/gen) + +if (MSVC) + target_compile_definitions(pioasm PRIVATE YY_NO_UNISTD_H) + target_compile_options(pioasm PRIVATE "/std:c++latest") +endif() + diff --git a/circuitpython/ports/raspberrypi/sdk/tools/pioasm/ada_output.cpp b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/ada_output.cpp new file mode 100644 index 0000000..8598f33 --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/ada_output.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2021 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Ada specifications generated by this assembler depend on the RP.PIO package, + * available in rp2040_hal. + * + * https://github.com/JeremyGrosser/rp2040_hal + * https://github.com/JeremyGrosser/pico_bsp + * https://github.com/JeremyGrosser/pico_examples + */ + +#include <algorithm> +#include <iostream> +#include "output_format.h" +#include "pio_disassembler.h" + +struct ada_output : public output_format { + struct factory { + factory() { + output_format::add(new ada_output()); + } + }; + + ada_output() : output_format("ada") {} + + std::string get_description() override { + return "Ada specification"; + } + + void output_symbols(FILE *out, const std::vector<compiled_source::symbol> &symbols) { + int count = 0; + for (const auto &s : symbols) { + if (!s.is_label) { + fprintf(out, "%s : constant := %d;\n", s.name.c_str(), s.value); + count++; + } + } + if (count) { + fprintf(out, "\n"); + count = 0; + } + for (const auto &s : symbols) { + if (s.is_label) { + fprintf(out, " Offset_%s : constant := %d;\n", s.name.c_str(), s.value); + count++; + } + } + if (count) { + fprintf(out, "\n"); + } + } + + void ada_case(std::string &identifier) { + for(std::string::size_type i = 0; i < identifier.size(); ++i) { + if ((i == 0) || (identifier[i - 1] == '_')) { + identifier[i] = toupper(identifier[i]); + } + } + } + + void header(FILE *out, const std::string msg, const int indent) { + const std::string dashes = std::string(msg.length() + 6, '-'); + const std::string indent_str= std::string(indent, ' '); + fprintf(out, "%s%s\n", indent_str.c_str(), dashes.c_str()); + fprintf(out, "%s-- %s --\n", indent_str.c_str(), msg.c_str()); + fprintf(out, "%s%s\n", indent_str.c_str(), dashes.c_str()); + fprintf(out, "\n"); + } + + int output(std::string destination, std::vector<std::string> output_options, + const compiled_source &source) override { + + for (const auto &program : source.programs) { + for(const auto &p : program.lang_opts) { + if (p.first.size() >= name.size() && p.first.compare(0, name.size(), name) == 0) { + std::cerr << "warning: " << name << " does not support output options; " << p.first << " lang_opt ignored.\n"; + } + } + } + + std::string package_name; + + switch (output_options.size()) { + case 0: + std::cerr << "error: missing package name options for Ada format" << std::endl; + return 1; + case 1: + package_name = output_options[0]; // Package name from command options + break; + default: + std::cerr << "error: too many options for Ada format" << std::endl; + return 1; + } + + FILE *out = open_single_output(destination); + if (!out) return 1; + + header(out, "This file is autogenerated by pioasm; do not edit!", 0); + fprintf(out, "pragma Style_Checks (Off);\n\n"); + fprintf(out, "with RP.PIO;\n\n"); + + fprintf(out, "package %s is\n", package_name.c_str()); + + for (const auto &program : source.programs) { + std::string trailing_comma = ", "; + + std::string prog_name= program.name; + ada_case(prog_name); + + fprintf(out, "\n"); + header(out, prog_name, 3); + + + output_symbols(out, source.global_symbols); + fprintf(out, " %s_Wrap_Target : constant := %d;\n", prog_name.c_str(), program.wrap_target); + fprintf(out, " %s_Wrap : constant := %d;\n", prog_name.c_str(), program.wrap); + fprintf(out, "\n"); + + output_symbols(out, program.symbols); + + fprintf(out, " %s_Program_Instructions : RP.PIO.Program := (\n", prog_name.c_str()); + for (int i = 0; i < (int)program.instructions.size(); i++) { + const auto &inst = program.instructions[i]; + if (i == program.wrap_target) { + fprintf(out, " -- .wrap_target\n"); + } + if (i == (int)program.instructions.size() - 1) { + trailing_comma = ");"; + } + fprintf(out, " 16#%04x#%s -- %2d: %s\n", inst, trailing_comma.c_str(), i, + disassemble(inst, program.sideset_bits_including_opt.get(), program.sideset_opt).c_str()); + if (i == program.wrap) { + fprintf(out, " -- .wrap\n"); + } + } + } + fprintf(out, "\n"); + fprintf(out, "end %s;\n", package_name.c_str()); + fclose(out); + return 0; + } +}; + +static ada_output::factory creator; diff --git a/circuitpython/ports/raspberrypi/sdk/tools/pioasm/c_sdk_output.cpp b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/c_sdk_output.cpp new file mode 100644 index 0000000..9388c0d --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/c_sdk_output.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <algorithm> +#include <iostream> +#include "output_format.h" +#include "pio_disassembler.h" + +struct c_sdk_output : public output_format { + struct factory { + factory() { + output_format::add(new c_sdk_output()); + } + }; + + c_sdk_output() : output_format("c-sdk") {} + + std::string get_description() override { + return "C header suitable for use with the Raspberry Pi Pico SDK"; + } + + void output_symbols(FILE *out, std::string prefix, const std::vector<compiled_source::symbol> &symbols) { + int count = 0; + for (const auto &s : symbols) { + if (!s.is_label) { + fprintf(out, "#define %s%s %d\n", prefix.c_str(), s.name.c_str(), s.value); + count++; + } + } + if (count) { + fprintf(out, "\n"); + count = 0; + } + for (const auto &s : symbols) { + if (s.is_label) { + fprintf(out, "#define %soffset_%s %du\n", prefix.c_str(), s.name.c_str(), s.value); + count++; + } + } + if (count) { + fprintf(out, "\n"); + } + } + + void header(FILE *out, std::string msg) { + std::string dashes = std::string(msg.length(), '-'); + fprintf(out, "// %s //\n", dashes.c_str()); + fprintf(out, "// %s //\n", msg.c_str()); + fprintf(out, "// %s //\n", dashes.c_str()); + fprintf(out, "\n"); + } + + int output(std::string destination, std::vector<std::string> output_options, + const compiled_source &source) override { + + for (const auto &program : source.programs) { + for(const auto &p : program.lang_opts) { + if (p.first.size() >= name.size() && p.first.compare(0, name.size(), name) == 0) { + std::cerr << "warning: " << name << " does not support output options; " << p.first << " lang_opt ignored.\n"; + } + } + } + FILE *out = open_single_output(destination); + if (!out) return 1; + + header(out, "This file is autogenerated by pioasm; do not edit!"); + + fprintf(out, "#pragma once\n"); + fprintf(out, "\n"); + fprintf(out, "#if !PICO_NO_HARDWARE\n"); + fprintf(out, "#include \"hardware/pio.h\"\n"); + fprintf(out, "#endif\n"); + fprintf(out, "\n"); + + output_symbols(out, "", source.global_symbols); + + for (const auto &program : source.programs) { + header(out, program.name); + + std::string prefix = program.name + "_"; + + fprintf(out, "#define %swrap_target %d\n", prefix.c_str(), program.wrap_target); + fprintf(out, "#define %swrap %d\n", prefix.c_str(), program.wrap); + fprintf(out, "\n"); + + output_symbols(out, prefix, program.symbols); + + fprintf(out, "static const uint16_t %sprogram_instructions[] = {\n", prefix.c_str()); + for (int i = 0; i < (int)program.instructions.size(); i++) { + const auto &inst = program.instructions[i]; + if (i == program.wrap_target) { + fprintf(out, " // .wrap_target\n"); + } + fprintf(out, " 0x%04x, // %2d: %s\n", inst, i, + disassemble(inst, program.sideset_bits_including_opt.get(), program.sideset_opt).c_str()); + if (i == program.wrap) { + fprintf(out, " // .wrap\n"); + } + } + fprintf(out, "};\n"); + fprintf(out, "\n"); + + fprintf(out, "#if !PICO_NO_HARDWARE\n"); + fprintf(out, "static const struct pio_program %sprogram = {\n", prefix.c_str()); + fprintf(out, " .instructions = %sprogram_instructions,\n", prefix.c_str()); + fprintf(out, " .length = %d,\n", (int) program.instructions.size()); + fprintf(out, " .origin = %d,\n", program.origin.get()); + fprintf(out, "};\n"); + fprintf(out, "\n"); + fprintf(out, "static inline pio_sm_config %sprogram_get_default_config(uint offset) {\n", prefix.c_str()); + fprintf(out, " pio_sm_config c = pio_get_default_sm_config();\n"); + fprintf(out, " sm_config_set_wrap(&c, offset + %swrap_target, offset + %swrap);\n", prefix.c_str(), + prefix.c_str()); + if (program.sideset_bits_including_opt.is_specified()) { + fprintf(out, " sm_config_set_sideset(&c, %d, %s, %s);\n", program.sideset_bits_including_opt.get(), + program.sideset_opt ? "true" : "false", + program.sideset_pindirs ? "true" : "false"); + } + fprintf(out, " return c;\n"); + fprintf(out, "}\n"); + + // todo maybe have some code blocks inside or outside here? + for(const auto& o : program.code_blocks) { + fprintf(out, "\n"); + if (o.first == name) { + for(const auto &contents : o.second) { + fprintf(out, "%s", contents.c_str()); + fprintf(out, "\n"); + } + } + } + + fprintf(out, "#endif\n"); + fprintf(out, "\n"); + } + if (out != stdout) { fclose(out); } + return 0; + } +}; + +static c_sdk_output::factory creator; diff --git a/circuitpython/ports/raspberrypi/sdk/tools/pioasm/gen/lexer.cpp b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/gen/lexer.cpp new file mode 100644 index 0000000..5de6626 --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/gen/lexer.cpp @@ -0,0 +1,2697 @@ + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +/* %not-for-header */ +/* %if-c-only */ +/* %if-not-reentrant */ + +/* %endif */ +/* %endif */ +/* %ok-for-header */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* %if-c++-only */ +/* %endif */ + +/* %if-c-only */ + +/* %endif */ + +/* %if-c-only */ + +/* %endif */ + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +/* %if-c-only */ + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> +/* %endif */ + +/* %if-tables-serialization */ +/* %endif */ +/* end standard C headers. */ + +/* begin standard C++ headers. */ +/* %if-c++-only */ +/* %endif */ + +/* %if-c-or-c++ */ +/* flex integer type definitions */ + +#ifndef YYFLEX_INTTYPES_DEFINED +#define YYFLEX_INTTYPES_DEFINED + +/* Prefer C99 integer types if available. */ +# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +/* Include <inttypes.h> and not <stdint.h> because Solaris 2.6 has the former + * and not the latter. + */ +#include <inttypes.h> +# define YYFLEX_USE_STDINT +# else +# if defined(_MSC_VER) && _MSC_VER >= 1600 +/* Visual C++ 2010 does not define __STDC_VERSION__ and has <stdint.h> but not + * <inttypes.h>. + */ +#include <stdint.h> +# define YYFLEX_USE_STDINT +# endif +# endif +# ifdef YYFLEX_USE_STDINT +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +# else +typedef unsigned char flex_uint8_t; +typedef short int flex_int16_t; +typedef unsigned short int flex_uint16_t; +# ifdef __STDC__ +typedef signed char flex_int8_t; +/* ISO C only requires at least 16 bits for int. */ +#include <limits.h> +# if UINT_MAX >= 4294967295 +# define YYFLEX_INT32_DEFINED +typedef int flex_int32_t; +typedef unsigned int flex_uint32_t; +# endif +# else +typedef char flex_int8_t; +# endif +# ifndef YYFLEX_INT32_DEFINED +typedef long int flex_int32_t; +typedef unsigned long int flex_uint32_t; +# endif +# endif +#endif /* YYFLEX_INTTYPES_DEFINED */ + +/* %endif */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* %not-for-header */ +/* Returned upon end-of-file. */ +#define YY_NULL 0 +/* %ok-for-header */ + +/* %not-for-header */ +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) +/* %ok-for-header */ + +/* %if-reentrant */ +/* %endif */ + +/* %if-not-reentrant */ + +/* %endif */ + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +/* %if-not-reentrant */ +extern int yyleng; +/* %endif */ + +/* %if-c-only */ +/* %if-not-reentrant */ +extern FILE *yyin, *yyout; +/* %endif */ +/* %endif */ + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + #define YY_LINENO_REWIND_TO(ptr) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { +/* %if-c-only */ + FILE *yy_input_file; +/* %endif */ + +/* %if-c++-only */ +/* %endif */ + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* %if-c-only Standard (non-C++) definition */ +/* %not-for-header */ +/* %if-not-reentrant */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */ +/* %endif */ +/* %ok-for-header */ + +/* %endif */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* %if-c-only Standard (non-C++) definition */ + +/* %if-not-reentrant */ +/* %not-for-header */ +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = NULL; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; +/* %ok-for-header */ + +/* %endif */ + +void yyrestart ( FILE *input_file ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size ); +void yy_delete_buffer ( YY_BUFFER_STATE b ); +void yy_flush_buffer ( YY_BUFFER_STATE b ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer ); +void yypop_buffer_state ( void ); + +static void yyensure_buffer_stack ( void ); +static void yy_load_buffer_state ( void ); +static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file ); +#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len ); + +/* %endif */ + +void *yyalloc ( yy_size_t ); +void *yyrealloc ( void *, yy_size_t ); +void yyfree ( void * ); + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* %% [1.0] yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here */ +/* Begin user sect3 */ + +#define yywrap() (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP + +#define FLEX_DEBUG +typedef flex_uint8_t YY_CHAR; + +FILE *yyin = NULL, *yyout = NULL; + +typedef int yy_state_type; + +extern int yylineno; +int yylineno = 1; + +extern char *yytext; +#ifdef yytext_ptr +#undef yytext_ptr +#endif +#define yytext_ptr yytext + +/* %% [1.5] DFA */ + +/* %if-c-only Standard (non-C++) definition */ + +static yy_state_type yy_get_previous_state ( void ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state ); +static int yy_get_next_buffer ( void ); +static void yynoreturn yy_fatal_error ( const char* msg ); + +/* %endif */ + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ +/* %% [2.0] code to fiddle yytext and yyleng for yymore() goes here \ */\ + yyleng = (int) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ +/* %% [3.0] code to copy yytext_ptr to yytext[] goes here, if %array \ */\ + (yy_c_buf_p) = yy_cp; +/* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */ +#define YY_NUM_RULES 95 +#define YY_END_OF_BUFFER 96 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_accept[263] = + { 0, + 0, 0, 7, 7, 11, 11, 0, 0, 96, 94, + 1, 2, 40, 94, 37, 28, 29, 34, 30, 23, + 33, 94, 35, 89, 89, 25, 93, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 73, 74, 92, 26, 27, 38, 36, 41, 94, + 7, 4, 5, 7, 11, 8, 12, 10, 19, 14, + 20, 21, 16, 16, 15, 1, 2, 39, 0, 0, + 31, 50, 50, 50, 50, 50, 50, 50, 22, 93, + 89, 0, 0, 24, 93, 92, 92, 92, 92, 92, + 92, 53, 92, 92, 92, 92, 92, 92, 92, 92, + + 92, 92, 75, 92, 92, 92, 92, 92, 92, 92, + 92, 0, 7, 4, 5, 6, 11, 8, 12, 9, + 19, 14, 20, 0, 13, 16, 19, 19, 0, 3, + 0, 50, 50, 50, 50, 50, 50, 50, 50, 91, + 90, 92, 92, 92, 92, 92, 92, 58, 77, 51, + 57, 92, 60, 92, 92, 87, 63, 78, 54, 67, + 92, 92, 92, 84, 59, 92, 92, 92, 92, 0, + 18, 17, 50, 50, 50, 50, 50, 50, 50, 92, + 92, 76, 68, 92, 92, 92, 92, 71, 92, 69, + 92, 70, 92, 56, 55, 64, 92, 52, 88, 0, + + 50, 50, 50, 50, 50, 45, 44, 80, 85, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 0, + 50, 50, 50, 50, 50, 50, 92, 82, 92, 86, + 92, 92, 61, 92, 92, 79, 32, 46, 50, 48, + 50, 50, 50, 83, 81, 92, 72, 65, 92, 50, + 42, 50, 50, 62, 66, 49, 47, 50, 50, 50, + 43, 0 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 4, 5, 1, 1, 6, 7, 1, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 18, 18, 18, 18, 18, 18, 18, 19, 20, 1, + 21, 1, 1, 1, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 1, 49, 50, 51, 1, 52, 53, 54, 55, + + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 82, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 83, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 84, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static const YY_CHAR yy_meta[85] = + { 0, + 1, 2, 3, 1, 2, 4, 1, 1, 1, 5, + 1, 1, 1, 1, 1, 6, 6, 6, 1, 1, + 2, 7, 7, 7, 7, 7, 7, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, + 8, 7, 7, 7, 7, 7, 7, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, + 1, 1, 1, 1 + } ; + +static const flex_int16_t yy_base[276] = + { 0, + 0, 0, 83, 85, 90, 92, 94, 101, 516, 605, + 513, 511, 492, 510, 605, 605, 605, 605, 605, 605, + 498, 88, 99, 118, 113, 490, 0, 0, 57, 74, + 63, 79, 113, 92, 91, 103, 107, 143, 124, 135, + 137, 0, 0, 134, 605, 605, 605, 605, 605, 420, + 0, 499, 497, 419, 0, 496, 494, 481, 0, 493, + 491, 488, 182, 170, 605, 399, 364, 605, 103, 131, + 605, 0, 138, 144, 145, 153, 171, 168, 605, 0, + 194, 200, 0, 605, 0, 0, 166, 182, 187, 188, + 193, 0, 183, 184, 187, 182, 203, 195, 203, 189, + + 194, 195, 0, 204, 238, 209, 203, 220, 224, 222, + 223, 283, 0, 363, 361, 0, 0, 360, 355, 605, + 0, 355, 353, 308, 285, 263, 248, 293, 265, 266, + 281, 0, 246, 249, 263, 258, 270, 257, 275, 269, + 0, 274, 277, 276, 266, 270, 263, 0, 0, 0, + 0, 273, 0, 285, 279, 0, 291, 296, 0, 313, + 298, 300, 310, 0, 0, 314, 300, 313, 319, 205, + 271, 370, 330, 344, 345, 346, 349, 351, 340, 346, + 340, 0, 0, 343, 348, 346, 359, 0, 355, 0, + 368, 0, 369, 0, 0, 380, 358, 0, 0, 159, + + 378, 117, 384, 376, 72, 0, 50, 0, 0, 375, + 384, 394, 391, 398, 395, 411, 410, 397, 398, 15, + 413, 404, 406, 420, 409, 410, 406, 0, 421, 0, + 432, 415, 0, 415, 431, 0, 605, 0, 421, 0, + 425, 434, 439, 0, 0, 440, 0, 0, 433, 434, + 0, 435, 438, 0, 0, 0, 0, 450, 454, 451, + 0, 605, 522, 530, 538, 546, 548, 556, 559, 567, + 575, 583, 591, 594, 597 + } ; + +static const flex_int16_t yy_def[276] = + { 0, + 262, 1, 263, 263, 264, 264, 265, 265, 262, 262, + 262, 262, 262, 266, 262, 262, 262, 262, 262, 262, + 262, 267, 262, 262, 262, 262, 268, 269, 269, 269, + 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, + 269, 269, 269, 269, 262, 262, 262, 262, 262, 262, + 270, 270, 262, 270, 271, 271, 262, 262, 272, 262, + 262, 273, 272, 272, 262, 262, 262, 262, 266, 266, + 262, 274, 274, 274, 274, 274, 274, 274, 262, 268, + 262, 262, 275, 262, 268, 269, 269, 269, 269, 269, + 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, + + 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, + 269, 262, 270, 270, 262, 270, 271, 271, 262, 262, + 272, 262, 262, 273, 273, 272, 272, 272, 266, 266, + 266, 274, 274, 274, 274, 274, 274, 274, 274, 262, + 275, 269, 269, 269, 269, 269, 269, 269, 269, 269, + 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, + 269, 269, 269, 269, 269, 269, 269, 269, 269, 262, + 272, 272, 274, 274, 274, 274, 274, 274, 274, 269, + 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, + 269, 269, 269, 269, 269, 269, 269, 269, 269, 262, + + 274, 274, 274, 274, 274, 274, 274, 269, 269, 269, + 269, 269, 269, 269, 269, 269, 269, 269, 269, 262, + 274, 274, 274, 274, 274, 274, 269, 269, 269, 269, + 269, 269, 269, 269, 269, 269, 262, 274, 274, 274, + 274, 274, 274, 269, 269, 269, 269, 269, 269, 274, + 274, 274, 274, 269, 269, 274, 274, 274, 274, 274, + 274, 0, 262, 262, 262, 262, 262, 262, 262, 262, + 262, 262, 262, 262, 262 + } ; + +static const flex_int16_t yy_nxt[690] = + { 0, + 10, 11, 12, 13, 10, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 25, 26, 27, + 10, 28, 29, 30, 28, 31, 28, 32, 28, 33, + 34, 28, 28, 35, 36, 37, 38, 28, 39, 40, + 28, 28, 28, 41, 42, 43, 44, 45, 46, 47, + 28, 28, 29, 30, 28, 31, 28, 32, 28, 33, + 34, 28, 28, 35, 36, 37, 38, 28, 39, 40, + 28, 28, 28, 41, 42, 43, 44, 10, 48, 10, + 49, 10, 10, 50, 52, 53, 52, 53, 54, 87, + 54, 56, 57, 56, 57, 60, 61, 237, 62, 58, + + 226, 58, 60, 61, 129, 62, 88, 89, 79, 63, + 64, 64, 73, 80, 65, 90, 63, 64, 64, 87, + 74, 65, 225, 75, 76, 95, 96, 77, 81, 81, + 81, 78, 131, 81, 81, 81, 88, 89, 97, 91, + 82, 99, 73, 100, 98, 90, 101, 92, 102, 106, + 74, 93, 94, 75, 76, 95, 96, 77, 110, 111, + 107, 78, 83, 133, 108, 134, 103, 222, 97, 91, + 82, 99, 104, 100, 98, 109, 101, 92, 102, 106, + 130, 93, 94, 135, 105, 126, 126, 126, 110, 111, + 107, 136, 83, 133, 108, 134, 103, 126, 126, 126, + + 137, 142, 104, 138, 127, 109, 139, 143, 130, 81, + 81, 81, 144, 135, 105, 140, 140, 145, 146, 147, + 148, 136, 149, 150, 151, 152, 128, 155, 156, 157, + 137, 142, 158, 138, 127, 159, 139, 143, 160, 153, + 220, 164, 144, 165, 166, 167, 154, 145, 146, 147, + 148, 168, 149, 150, 151, 152, 128, 155, 156, 157, + 161, 169, 158, 171, 171, 159, 129, 129, 160, 153, + 162, 164, 173, 165, 166, 167, 154, 163, 126, 126, + 126, 168, 131, 174, 140, 140, 171, 171, 200, 125, + 161, 169, 175, 176, 177, 178, 179, 180, 181, 182, + + 162, 183, 173, 184, 185, 186, 187, 163, 172, 172, + 172, 188, 125, 174, 172, 172, 172, 172, 172, 172, + 189, 190, 175, 176, 177, 178, 179, 180, 181, 182, + 193, 183, 194, 184, 185, 186, 187, 191, 195, 196, + 197, 188, 130, 130, 172, 172, 172, 172, 172, 172, + 189, 190, 192, 198, 199, 123, 122, 119, 130, 201, + 193, 118, 194, 115, 114, 170, 67, 191, 195, 196, + 197, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 192, 198, 199, 172, 172, 172, 213, 201, + 214, 172, 172, 172, 172, 172, 172, 215, 216, 219, + + 66, 202, 203, 204, 205, 206, 207, 208, 209, 210, + 211, 212, 221, 223, 224, 227, 228, 229, 213, 217, + 214, 172, 172, 172, 172, 172, 172, 215, 216, 219, + 218, 230, 231, 232, 233, 234, 235, 236, 238, 239, + 240, 241, 221, 223, 224, 227, 228, 229, 242, 217, + 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, + 253, 230, 231, 232, 233, 234, 235, 236, 238, 239, + 240, 241, 254, 255, 256, 257, 258, 259, 242, 260, + 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, + 253, 261, 125, 123, 122, 120, 119, 118, 116, 115, + + 114, 112, 254, 255, 256, 257, 258, 259, 84, 260, + 71, 70, 68, 67, 66, 262, 262, 262, 262, 262, + 262, 261, 51, 51, 51, 51, 51, 51, 51, 51, + 55, 55, 55, 55, 55, 55, 55, 55, 59, 59, + 59, 59, 59, 59, 59, 59, 69, 69, 262, 262, + 69, 69, 69, 69, 72, 72, 85, 85, 262, 85, + 85, 85, 85, 85, 86, 86, 86, 113, 113, 262, + 113, 113, 113, 113, 113, 117, 117, 262, 117, 262, + 117, 117, 117, 121, 262, 262, 121, 121, 121, 121, + 121, 124, 124, 262, 124, 124, 124, 124, 124, 132, + + 132, 132, 141, 141, 9, 262, 262, 262, 262, 262, + 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, + 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, + 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, + 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, + 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, + 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, + 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, + 262, 262, 262, 262, 262, 262, 262, 262, 262 + } ; + +static const flex_int16_t yy_chk[690] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3, 3, 4, 4, 3, 29, + 4, 5, 5, 6, 6, 7, 7, 220, 7, 5, + + 207, 6, 8, 8, 69, 8, 30, 31, 23, 7, + 7, 7, 22, 23, 7, 32, 8, 8, 8, 29, + 22, 8, 205, 22, 22, 34, 35, 22, 25, 25, + 25, 22, 70, 24, 24, 24, 30, 31, 36, 33, + 24, 37, 22, 37, 36, 32, 37, 33, 37, 39, + 22, 33, 33, 22, 22, 34, 35, 22, 41, 44, + 40, 22, 24, 73, 40, 74, 38, 202, 36, 33, + 24, 37, 38, 37, 36, 40, 37, 33, 37, 39, + 69, 33, 33, 75, 38, 64, 64, 64, 41, 44, + 40, 76, 24, 73, 40, 74, 38, 63, 63, 63, + + 77, 87, 38, 78, 63, 40, 78, 88, 70, 81, + 81, 81, 89, 75, 38, 82, 82, 90, 91, 91, + 93, 76, 94, 95, 96, 97, 63, 98, 99, 100, + 77, 87, 101, 78, 63, 102, 78, 88, 104, 97, + 200, 106, 89, 107, 108, 109, 97, 90, 91, 91, + 93, 110, 94, 95, 96, 97, 63, 98, 99, 100, + 105, 111, 101, 127, 127, 102, 129, 130, 104, 97, + 105, 106, 133, 107, 108, 109, 97, 105, 126, 126, + 126, 110, 131, 134, 140, 140, 171, 171, 170, 125, + 105, 111, 135, 136, 137, 138, 139, 142, 143, 144, + + 105, 145, 133, 146, 147, 152, 154, 105, 128, 128, + 128, 155, 124, 134, 128, 128, 128, 128, 128, 128, + 157, 158, 135, 136, 137, 138, 139, 142, 143, 144, + 161, 145, 162, 146, 147, 152, 154, 160, 163, 166, + 167, 155, 129, 130, 128, 128, 128, 128, 128, 128, + 157, 158, 160, 168, 169, 123, 122, 119, 131, 173, + 161, 118, 162, 115, 114, 112, 67, 160, 163, 166, + 167, 174, 175, 176, 177, 178, 179, 180, 181, 184, + 185, 186, 160, 168, 169, 172, 172, 172, 187, 173, + 189, 172, 172, 172, 172, 172, 172, 191, 193, 197, + + 66, 174, 175, 176, 177, 178, 179, 180, 181, 184, + 185, 186, 201, 203, 204, 210, 211, 212, 187, 196, + 189, 172, 172, 172, 172, 172, 172, 191, 193, 197, + 196, 213, 214, 215, 216, 217, 218, 219, 221, 222, + 223, 224, 201, 203, 204, 210, 211, 212, 225, 196, + 226, 227, 229, 231, 232, 234, 235, 239, 241, 242, + 243, 213, 214, 215, 216, 217, 218, 219, 221, 222, + 223, 224, 246, 249, 250, 252, 253, 258, 225, 259, + 226, 227, 229, 231, 232, 234, 235, 239, 241, 242, + 243, 260, 62, 61, 60, 58, 57, 56, 54, 53, + + 52, 50, 246, 249, 250, 252, 253, 258, 26, 259, + 21, 14, 13, 12, 11, 9, 0, 0, 0, 0, + 0, 260, 263, 263, 263, 263, 263, 263, 263, 263, + 264, 264, 264, 264, 264, 264, 264, 264, 265, 265, + 265, 265, 265, 265, 265, 265, 266, 266, 0, 0, + 266, 266, 266, 266, 267, 267, 268, 268, 0, 268, + 268, 268, 268, 268, 269, 269, 269, 270, 270, 0, + 270, 270, 270, 270, 270, 271, 271, 0, 271, 0, + 271, 271, 271, 272, 0, 0, 272, 272, 272, 272, + 272, 273, 273, 0, 273, 273, 273, 273, 273, 274, + + 274, 274, 275, 275, 262, 262, 262, 262, 262, 262, + 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, + 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, + 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, + 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, + 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, + 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, + 262, 262, 262, 262, 262, 262, 262, 262, 262, 262, + 262, 262, 262, 262, 262, 262, 262, 262, 262 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +extern int yy_flex_debug; +int yy_flex_debug = 1; + +static const flex_int16_t yy_rule_linenum[95] = + { 0, + 65, 66, 68, 79, 80, 81, 82, 86, 87, 88, + 89, 90, 94, 95, 96, 97, 98, 99, 100, 101, + 102, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, + 147, 149, 150, 151, 152, 153, 154, 155, 156, 158, + 159, 160, 161, 162, 163, 164, 165, 166, 167, 169, + 170, 171, 172, 173, 175, 176, 178, 179, 183, 184, + 185, 187, 189, 191 + + } ; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "lexer.ll" +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#line 8 "lexer.ll" +# include <cerrno> +# include <climits> +# include <cstdlib> +# include <cstring> +# include <string> +# include "pio_assembler.h" +# include "parser.hpp" + +#ifdef _MSC_VER +#pragma warning(disable : 4996) // fopen +#endif + +#define YY_NO_INPUT 1 + yy::parser::symbol_type make_INT(const std::string &s, const yy::parser::location_type& loc); + yy::parser::symbol_type make_HEX(const std::string &s, const yy::parser::location_type& loc); + yy::parser::symbol_type make_BINARY(const std::string &s, const yy::parser::location_type& loc); + // Code run each time a pattern is matched. + # define YY_USER_ACTION loc.columns (yyleng); + +#define INITIAL 0 +#define code_block 1 +#define c_comment 2 +#define lang_opt 3 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +/* %if-c-only */ +#include <unistd.h> +/* %endif */ +/* %if-c++-only */ +/* %endif */ +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* %if-c-only Reentrant structure and macros (non-C++). */ +/* %if-reentrant */ +/* %if-c-only */ + +static int yy_init_globals ( void ); + +/* %endif */ +/* %if-reentrant */ +/* %endif */ +/* %endif End reentrant structures and macros. */ + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( void ); + +int yyget_debug ( void ); + +void yyset_debug ( int debug_flag ); + +YY_EXTRA_TYPE yyget_extra ( void ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined ); + +FILE *yyget_in ( void ); + +void yyset_in ( FILE * _in_str ); + +FILE *yyget_out ( void ); + +void yyset_out ( FILE * _out_str ); + + int yyget_leng ( void ); + +char *yyget_text ( void ); + +int yyget_lineno ( void ); + +void yyset_lineno ( int _line_number ); + +/* %if-bison-bridge */ +/* %endif */ + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( void ); +#else +extern int yywrap ( void ); +#endif +#endif + +/* %not-for-header */ +#ifndef YY_NO_UNPUT + +#endif +/* %ok-for-header */ + +/* %endif */ + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * ); +#endif + +#ifndef YY_NO_INPUT +/* %if-c-only Standard (non-C++) definition */ +/* %not-for-header */ +#ifdef __cplusplus +static int yyinput ( void ); +#else +static int input ( void ); +#endif +/* %ok-for-header */ + +/* %endif */ +#endif + +/* %if-c-only */ + +/* %endif */ + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* %if-c-only Standard (non-C++) definition */ +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +/* %endif */ +/* %if-c++-only C++ definition */ +/* %endif */ +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ +/* %% [5.0] fread()/read() definition of YY_INPUT goes here unless we're doing C++ \ */\ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ +/* %if-c++-only C++ definition \ */\ +/* %endif */ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +/* %if-c-only */ +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +#endif + +/* %if-tables-serialization structures and prototypes */ +/* %not-for-header */ +/* %ok-for-header */ + +/* %not-for-header */ +/* %tables-yydmap generated elements */ +/* %endif */ +/* end tables serialization structures and prototypes */ + +/* %ok-for-header */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 +/* %if-c-only Standard (non-C++) definition */ + +extern int yylex (void); + +#define YY_DECL int yylex (void) +/* %endif */ +/* %if-c++-only C++ definition */ +/* %endif */ +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +/* %% [6.0] YY_RULE_SETUP definition goes here */ +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/* %not-for-header */ +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! yyin ) +/* %if-c-only */ + yyin = stdin; +/* %endif */ +/* %if-c++-only */ +/* %endif */ + + if ( ! yyout ) +/* %if-c-only */ + yyout = stdout; +/* %endif */ +/* %if-c++-only */ +/* %endif */ + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE ); + } + + yy_load_buffer_state( ); + } + + { +/* %% [7.0] user's declarations go here */ + + std::string code_block_contents; + yy::location code_block_start; + + // A handy shortcut to the location held by the pio_assembler. + yy::location& loc = pioasm.location; + // Code run each time yylex is called. + loc.step(); + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { +/* %% [8.0] yymore()-related code goes here */ + yy_cp = (yy_c_buf_p); + + /* Support of yytext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + +/* %% [9.0] code to set up and find next match goes here */ + yy_current_state = (yy_start); +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 263 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_current_state != 262 ); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + +yy_find_action: +/* %% [10.0] code to find the action number goes here */ + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + +/* %% [11.0] code for yylineno update goes here */ + +do_action: /* This label is used only to access EOF actions. */ + +/* %% [12.0] debug code goes here */ + if ( yy_flex_debug ) + { + if ( yy_act == 0 ) + fprintf( stderr, "--scanner backing up\n" ); + else if ( yy_act < 95 ) + fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n", + (long)yy_rule_linenum[yy_act], yytext ); + else if ( yy_act == 95 ) + fprintf( stderr, "--accepting default rule (\"%s\")\n", + yytext ); + else if ( yy_act == 96 ) + fprintf( stderr, "--(end of buffer or a NUL)\n" ); + else + fprintf( stderr, "--EOF (start condition %d)\n", YY_START ); + } + + switch ( yy_act ) + { /* beginning of action switch */ +/* %% [13.0] actions go here */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + +case 1: +YY_RULE_SETUP +loc.step(); + YY_BREAK +case 2: +/* rule 2 can match eol */ +YY_RULE_SETUP +{ auto loc_newline = loc; loc_newline.end = loc_newline.begin; loc.lines(yyleng); loc.step(); return yy::parser::make_NEWLINE(loc_newline); } + YY_BREAK +case 3: +YY_RULE_SETUP +{ + BEGIN(code_block); + code_block_contents = ""; + code_block_start = loc; + std::string tmp(yytext); + tmp = tmp.substr(1, tmp.length() - 2); + tmp = tmp.erase(0, tmp.find_first_not_of(" \t")); + tmp = tmp.erase(tmp.find_last_not_of(" \t") + 1); + return yy::parser::make_CODE_BLOCK_START( tmp, loc); + } + YY_BREAK + +case 4: +YY_RULE_SETUP +loc.step(); + YY_BREAK +case 5: +/* rule 5 can match eol */ +YY_RULE_SETUP +{ auto loc_newline = loc; loc_newline.end = loc_newline.begin; loc.lines(yyleng); loc.step(); } + YY_BREAK +case 6: +YY_RULE_SETUP +{ BEGIN(INITIAL); auto loc2 = loc; loc2.begin = code_block_start.begin; return yy::parser::make_CODE_BLOCK_CONTENTS(code_block_contents, loc2); } + YY_BREAK +case 7: +YY_RULE_SETUP +{ code_block_contents += std::string(yytext) + "\n"; } + YY_BREAK + +case 8: +YY_RULE_SETUP +loc.step(); + YY_BREAK +case 9: +YY_RULE_SETUP +{ BEGIN(INITIAL); } + YY_BREAK +case 10: +YY_RULE_SETUP +{ } + YY_BREAK +case 11: +YY_RULE_SETUP +{ } + YY_BREAK +case 12: +/* rule 12 can match eol */ +YY_RULE_SETUP +{ auto loc_newline = loc; loc_newline.end = loc_newline.begin; loc.lines(yyleng); loc.step(); } + YY_BREAK + +case 13: +YY_RULE_SETUP +return yy::parser::make_STRING(yytext, loc); + YY_BREAK +case 14: +YY_RULE_SETUP +loc.step(); + YY_BREAK +case 15: +YY_RULE_SETUP +return yy::parser::make_EQUAL(loc); + YY_BREAK +case 16: +YY_RULE_SETUP +return make_INT(yytext, loc); + YY_BREAK +case 17: +YY_RULE_SETUP +return make_HEX(yytext, loc); + YY_BREAK +case 18: +YY_RULE_SETUP +return make_BINARY(yytext, loc); + YY_BREAK +case 19: +YY_RULE_SETUP +return yy::parser::make_NON_WS(yytext, loc); + YY_BREAK +case 20: +/* rule 20 can match eol */ +YY_RULE_SETUP +{ BEGIN(INITIAL); auto loc_newline = loc; loc_newline.end = loc_newline.begin; loc.lines(yyleng); loc.step(); return yy::parser::make_NEWLINE(loc_newline); } + YY_BREAK +case 21: +YY_RULE_SETUP +{ throw yy::parser::syntax_error(loc, "invalid character: " + std::string(yytext)); } + YY_BREAK + +case 22: +YY_RULE_SETUP +{ BEGIN(c_comment); } + YY_BREAK +case 23: +YY_RULE_SETUP +return yy::parser::make_COMMA(loc); + YY_BREAK +case 24: +YY_RULE_SETUP +return yy::parser::make_REVERSE(loc); + YY_BREAK +case 25: +YY_RULE_SETUP +return yy::parser::make_COLON(loc); + YY_BREAK +case 26: +YY_RULE_SETUP +return yy::parser::make_LBRACKET(loc); + YY_BREAK +case 27: +YY_RULE_SETUP +return yy::parser::make_RBRACKET(loc); + YY_BREAK +case 28: +YY_RULE_SETUP +return yy::parser::make_LPAREN(loc); + YY_BREAK +case 29: +YY_RULE_SETUP +return yy::parser::make_RPAREN(loc); + YY_BREAK +case 30: +YY_RULE_SETUP +return yy::parser::make_PLUS(loc); + YY_BREAK +case 31: +YY_RULE_SETUP +return yy::parser::make_POST_DECREMENT(loc); + YY_BREAK +case 32: +YY_RULE_SETUP +return yy::parser::make_POST_DECREMENT(loc); + YY_BREAK +case 33: +YY_RULE_SETUP +return yy::parser::make_MINUS(loc); + YY_BREAK +case 34: +YY_RULE_SETUP +return yy::parser::make_MULTIPLY(loc); + YY_BREAK +case 35: +YY_RULE_SETUP +return yy::parser::make_DIVIDE(loc); + YY_BREAK +case 36: +YY_RULE_SETUP +return yy::parser::make_OR(loc); + YY_BREAK +case 37: +YY_RULE_SETUP +return yy::parser::make_AND(loc); + YY_BREAK +case 38: +YY_RULE_SETUP +return yy::parser::make_XOR(loc); + YY_BREAK +case 39: +YY_RULE_SETUP +return yy::parser::make_NOT_EQUAL(loc); + YY_BREAK +case 40: +YY_RULE_SETUP +return yy::parser::make_NOT(loc); + YY_BREAK +case 41: +YY_RULE_SETUP +return yy::parser::make_NOT(loc); + YY_BREAK +case 42: +YY_RULE_SETUP +return yy::parser::make_PROGRAM(loc); + YY_BREAK +case 43: +YY_RULE_SETUP +return yy::parser::make_WRAP_TARGET(loc); + YY_BREAK +case 44: +YY_RULE_SETUP +return yy::parser::make_WRAP(loc); + YY_BREAK +case 45: +YY_RULE_SETUP +return yy::parser::make_WORD(loc); + YY_BREAK +case 46: +YY_RULE_SETUP +return yy::parser::make_DEFINE(loc); + YY_BREAK +case 47: +YY_RULE_SETUP +return yy::parser::make_SIDE_SET(loc); + YY_BREAK +case 48: +YY_RULE_SETUP +return yy::parser::make_ORIGIN(loc); + YY_BREAK +case 49: +YY_RULE_SETUP +{ BEGIN(lang_opt); return yy::parser::make_LANG_OPT(loc); } + YY_BREAK +case 50: +YY_RULE_SETUP +return yy::parser::make_UNKNOWN_DIRECTIVE(yytext, loc); + YY_BREAK +case 51: +YY_RULE_SETUP +return yy::parser::make_JMP(loc); + YY_BREAK +case 52: +YY_RULE_SETUP +return yy::parser::make_WAIT(loc); + YY_BREAK +case 53: +YY_RULE_SETUP +return yy::parser::make_IN(loc); + YY_BREAK +case 54: +YY_RULE_SETUP +return yy::parser::make_OUT(loc); + YY_BREAK +case 55: +YY_RULE_SETUP +return yy::parser::make_PUSH(loc); + YY_BREAK +case 56: +YY_RULE_SETUP +return yy::parser::make_PULL(loc); + YY_BREAK +case 57: +YY_RULE_SETUP +return yy::parser::make_MOV(loc); + YY_BREAK +case 58: +YY_RULE_SETUP +return yy::parser::make_IRQ(loc); + YY_BREAK +case 59: +YY_RULE_SETUP +return yy::parser::make_SET(loc); + YY_BREAK +case 60: +YY_RULE_SETUP +return yy::parser::make_NOP(loc); + YY_BREAK +case 61: +YY_RULE_SETUP +return yy::parser::make_PUBLIC(loc); + YY_BREAK +case 62: +YY_RULE_SETUP +return yy::parser::make_OPTIONAL(loc); + YY_BREAK +case 63: +YY_RULE_SETUP +return yy::parser::make_OPTIONAL(loc); + YY_BREAK +case 64: +YY_RULE_SETUP +return yy::parser::make_SIDE(loc); + YY_BREAK +case 65: +YY_RULE_SETUP +return yy::parser::make_SIDE(loc); + YY_BREAK +case 66: +YY_RULE_SETUP +return yy::parser::make_SIDE(loc); + YY_BREAK +case 67: +YY_RULE_SETUP +return yy::parser::make_PIN(loc); + YY_BREAK +case 68: +YY_RULE_SETUP +return yy::parser::make_GPIO(loc); + YY_BREAK +case 69: +YY_RULE_SETUP +return yy::parser::make_OSRE(loc); + YY_BREAK +case 70: +YY_RULE_SETUP +return yy::parser::make_PINS(loc); + YY_BREAK +case 71: +YY_RULE_SETUP +return yy::parser::make_NULL(loc); + YY_BREAK +case 72: +YY_RULE_SETUP +return yy::parser::make_PINDIRS(loc); + YY_BREAK +case 73: +YY_RULE_SETUP +return yy::parser::make_X(loc); + YY_BREAK +case 74: +YY_RULE_SETUP +return yy::parser::make_Y(loc); + YY_BREAK +case 75: +YY_RULE_SETUP +return yy::parser::make_PC(loc); + YY_BREAK +case 76: +YY_RULE_SETUP +return yy::parser::make_EXEC(loc); + YY_BREAK +case 77: +YY_RULE_SETUP +return yy::parser::make_ISR(loc); + YY_BREAK +case 78: +YY_RULE_SETUP +return yy::parser::make_OSR(loc); + YY_BREAK +case 79: +YY_RULE_SETUP +return yy::parser::make_STATUS(loc); + YY_BREAK +case 80: +YY_RULE_SETUP +return yy::parser::make_BLOCK(loc); + YY_BREAK +case 81: +YY_RULE_SETUP +return yy::parser::make_NOBLOCK(loc); + YY_BREAK +case 82: +YY_RULE_SETUP +return yy::parser::make_IFFULL(loc); + YY_BREAK +case 83: +YY_RULE_SETUP +return yy::parser::make_IFEMPTY(loc); + YY_BREAK +case 84: +YY_RULE_SETUP +return yy::parser::make_REL(loc); + YY_BREAK +case 85: +YY_RULE_SETUP +return yy::parser::make_CLEAR(loc); + YY_BREAK +case 86: +YY_RULE_SETUP +return yy::parser::make_NOWAIT(loc); + YY_BREAK +case 87: +YY_RULE_SETUP +return yy::parser::make_INT(1, loc); + YY_BREAK +case 88: +YY_RULE_SETUP +return yy::parser::make_INT(0, loc); + YY_BREAK +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(code_block): +case YY_STATE_EOF(c_comment): +case YY_STATE_EOF(lang_opt): +return yy::parser::make_END(loc); + YY_BREAK +case 89: +YY_RULE_SETUP +return make_INT(yytext, loc); + YY_BREAK +case 90: +YY_RULE_SETUP +return make_HEX(yytext, loc); + YY_BREAK +case 91: +YY_RULE_SETUP +return make_BINARY(yytext, loc); + YY_BREAK +case 92: +YY_RULE_SETUP +return yy::parser::make_ID(yytext, loc); + YY_BREAK +case 93: +YY_RULE_SETUP +{ } + YY_BREAK +case 94: +YY_RULE_SETUP +{ throw yy::parser::syntax_error(loc, "invalid character: " + std::string(yytext)); } + YY_BREAK +case 95: +YY_RULE_SETUP +ECHO; + YY_BREAK + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; +/* %if-c-only */ + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; +/* %endif */ +/* %if-c++-only */ +/* %endif */ + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { +/* %% [14.0] code to do back-up for compressed tables and set up yy_cp goes here */ + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( yywrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ +/* %ok-for-header */ + +/* %if-c++-only */ +/* %not-for-header */ +/* %ok-for-header */ + +/* %endif */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +/* %if-c-only */ +static int yy_get_next_buffer (void) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = (yytext_ptr); + int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc( (void *) b->yy_ch_buf, + (yy_size_t) (b->yy_buf_size + 2) ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = NULL; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +/* %if-c-only */ +/* %not-for-header */ + static yy_state_type yy_get_previous_state (void) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + yy_state_type yy_current_state; + char *yy_cp; + +/* %% [15.0] code to get the start state into yy_current_state goes here */ + yy_current_state = (yy_start); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { +/* %% [16.0] code to find the next state goes here */ + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 263 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ +/* %if-c-only */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + int yy_is_jam; + /* %% [17.0] code to find the next state, and perhaps do backing up, goes here */ + char *yy_cp = (yy_c_buf_p); + + YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 263 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 262); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT +/* %if-c-only */ + +/* %endif */ +#endif + +/* %if-c-only */ +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + int offset = (int) ((yy_c_buf_p) - (yytext_ptr)); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( ) ) + return 0; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve yytext */ + (yy_hold_char) = *++(yy_c_buf_p); + +/* %% [19.0] update BOL and yylineno */ + + return c; +} +/* %if-c-only */ +#endif /* ifndef YY_NO_INPUT */ +/* %endif */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ +/* %if-c-only */ + void yyrestart (FILE * input_file ) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE ); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file ); + yy_load_buffer_state( ); +} + +/* %if-c++-only */ +/* %endif */ + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ +/* %if-c-only */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +/* %if-c-only */ +static void yy_load_buffer_state (void) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; +/* %if-c-only */ + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; +/* %endif */ +/* %if-c++-only */ +/* %endif */ + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ +/* %if-c-only */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; +} + +/* %if-c++-only */ +/* %endif */ + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * + */ +/* %if-c-only */ + void yy_delete_buffer (YY_BUFFER_STATE b ) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree( (void *) b->yy_ch_buf ); + + yyfree( (void *) b ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ +/* %if-c-only */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) +/* %endif */ +/* %if-c++-only */ +/* %endif */ + +{ + int oerrno = errno; + + yy_flush_buffer( b ); + +/* %if-c-only */ + b->yy_input_file = file; +/* %endif */ +/* %if-c++-only */ +/* %endif */ + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + +/* %if-c-only */ + + b->yy_is_interactive = 0; + +/* %endif */ +/* %if-c++-only */ +/* %endif */ + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ +/* %if-c-only */ + void yy_flush_buffer (YY_BUFFER_STATE b ) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( ); +} + +/* %if-c-or-c++ */ +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +/* %if-c-only */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} +/* %endif */ + +/* %if-c-or-c++ */ +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +/* %if-c-only */ +void yypop_buffer_state (void) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} +/* %endif */ + +/* %if-c-or-c++ */ +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +/* %if-c-only */ +static void yyensure_buffer_stack (void) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + yy_size_t num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} +/* %endif */ + +/* %if-c-only */ +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; +} +/* %endif */ + +/* %if-c-only */ +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (const char * yystr ) +{ + + return yy_scan_bytes( yystr, (int) strlen(yystr) ); +} +/* %endif */ + +/* %if-c-only */ +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) yyalloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} +/* %endif */ + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +/* %if-c-only */ +static void yynoreturn yy_fatal_error (const char* msg ) +{ + fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} +/* %endif */ +/* %if-c++-only */ +/* %endif */ + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = (yy_hold_char); \ + (yy_c_buf_p) = yytext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/* %if-c-only */ +/* %if-reentrant */ +/* %endif */ + +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} + +/** Get the input stream. + * + */ +FILE *yyget_in (void) +{ + return yyin; +} + +/** Get the output stream. + * + */ +FILE *yyget_out (void) +{ + return yyout; +} + +/** Get the length of the current token. + * + */ +int yyget_leng (void) +{ + return yyleng; +} + +/** Get the current token. + * + */ + +char *yyget_text (void) +{ + return yytext; +} + +/* %if-reentrant */ +/* %endif */ + +/** Set the current line number. + * @param _line_number line number + * + */ +void yyset_lineno (int _line_number ) +{ + + yylineno = _line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str ) +{ + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str ) +{ + yyout = _out_str ; +} + +int yyget_debug (void) +{ + return yy_flex_debug; +} + +void yyset_debug (int _bdebug ) +{ + yy_flex_debug = _bdebug ; +} + +/* %endif */ + +/* %if-reentrant */ +/* %if-bison-bridge */ +/* %endif */ +/* %endif if-c-only */ + +/* %if-c-only */ +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + (yy_buffer_stack) = NULL; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = NULL; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} +/* %endif */ + +/* %if-c-only SNIP! this currently causes conflicts with the c++ scanner */ +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer( YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(); + } + + /* Destroy the stack itself. */ + yyfree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( ); + +/* %if-reentrant */ +/* %endif */ + return 0; +} +/* %endif */ + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n ) +{ + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s ) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size ) +{ + return malloc(size); +} + +void *yyrealloc (void * ptr, yy_size_t size ) +{ + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void yyfree (void * ptr ) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +/* %if-tables-serialization definitions */ +/* %define-yytables The name for this specific scanner's tables. */ +/* %endif */ + +/* %ok-for-header */ + +yy::parser::symbol_type make_INT(const std::string &s, const yy::parser::location_type& loc) +{ + errno = 0; + long n = strtol (s.c_str(), NULL, 10); + if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE)) + throw yy::parser::syntax_error (loc, "integer is out of range: " + s); + return yy::parser::make_INT((int) n, loc); +} + +yy::parser::symbol_type make_HEX(const std::string &s, const yy::parser::location_type& loc) +{ + errno = 0; + long n = strtol (s.c_str() + 2, NULL, 16); + if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE)) + throw yy::parser::syntax_error (loc, "hex is out of range: " + s); + return yy::parser::make_INT((int) n, loc); +} + +yy::parser::symbol_type make_BINARY(const std::string &s, const yy::parser::location_type& loc) +{ + errno = 0; + long n = strtol (s.c_str()+2, NULL, 2); + if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE)) + throw yy::parser::syntax_error (loc, "binary is out of range: " + s); + return yy::parser::make_INT((int) n, loc); +} + +void pio_assembler::scan_begin () +{ + yy_flex_debug = false; + if (source.empty () || source == "-") + yyin = stdin; + else if (!(yyin = fopen (source.c_str (), "r"))) + { + std::cerr << "cannot open " << source << ": " << strerror(errno) << '\n'; + exit (EXIT_FAILURE); + } +} + +void pio_assembler::scan_end () +{ + fclose (yyin); +} + diff --git a/circuitpython/ports/raspberrypi/sdk/tools/pioasm/gen/location.h b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/gen/location.h new file mode 100644 index 0000000..4965682 --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/gen/location.h @@ -0,0 +1,302 @@ +// A Bison parser, made by GNU Bison 3.7.2. + +// Locations for Bison parsers in C++ + +// Copyright (C) 2002-2015, 2018-2020 Free Software Foundation, Inc. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +// As a special exception, you may create a larger work that contains +// part or all of the Bison parser skeleton and distribute that work +// under terms of your choice, so long as that work isn't itself a +// parser generator using the skeleton or a modified version thereof +// as a parser skeleton. Alternatively, if you modify or redistribute +// the parser skeleton itself, you may (at your option) remove this +// special exception, which will cause the skeleton and the resulting +// Bison output files to be licensed under the GNU General Public +// License without this special exception. + +// This special exception was added by the Free Software Foundation in +// version 2.2 of Bison. + +/** + ** \file pico_sdk/tools/pioasm/gen/location.h + ** Define the yy::location class. + */ + +#ifndef YY_YY_HOME_GRAHAM_DEV_MU_PICO_SDK_TOOLS_PIOASM_GEN_LOCATION_H_INCLUDED +# define YY_YY_HOME_GRAHAM_DEV_MU_PICO_SDK_TOOLS_PIOASM_GEN_LOCATION_H_INCLUDED + +# include <iostream> +# include <string> + +# ifndef YY_NULLPTR +# if defined __cplusplus +# if 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# else +# define YY_NULLPTR ((void*)0) +# endif +# endif + +namespace yy { + + /// A point in a source file. + class position + { + public: + /// Type for file name. + typedef const std::string filename_type; + /// Type for line and column numbers. + typedef int counter_type; + + /// Construct a position. + explicit position (filename_type* f = YY_NULLPTR, + counter_type l = 1, + counter_type c = 1) + : filename (f) + , line (l) + , column (c) + {} + + + /// Initialization. + void initialize (filename_type* fn = YY_NULLPTR, + counter_type l = 1, + counter_type c = 1) + { + filename = fn; + line = l; + column = c; + } + + /** \name Line and Column related manipulators + ** \{ */ + /// (line related) Advance to the COUNT next lines. + void lines (counter_type count = 1) + { + if (count) + { + column = 1; + line = add_ (line, count, 1); + } + } + + /// (column related) Advance to the COUNT next columns. + void columns (counter_type count = 1) + { + column = add_ (column, count, 1); + } + /** \} */ + + /// File name to which this position refers. + filename_type* filename; + /// Current line number. + counter_type line; + /// Current column number. + counter_type column; + + private: + /// Compute max (min, lhs+rhs). + static counter_type add_ (counter_type lhs, counter_type rhs, counter_type min) + { + return lhs + rhs < min ? min : lhs + rhs; + } + }; + + /// Add \a width columns, in place. + inline position& + operator+= (position& res, position::counter_type width) + { + res.columns (width); + return res; + } + + /// Add \a width columns. + inline position + operator+ (position res, position::counter_type width) + { + return res += width; + } + + /// Subtract \a width columns, in place. + inline position& + operator-= (position& res, position::counter_type width) + { + return res += -width; + } + + /// Subtract \a width columns. + inline position + operator- (position res, position::counter_type width) + { + return res -= width; + } + + /** \brief Intercept output stream redirection. + ** \param ostr the destination output stream + ** \param pos a reference to the position to redirect + */ + template <typename YYChar> + std::basic_ostream<YYChar>& + operator<< (std::basic_ostream<YYChar>& ostr, const position& pos) + { + if (pos.filename) + ostr << *pos.filename << ':'; + return ostr << pos.line << '.' << pos.column; + } + + /// Two points in a source file. + class location + { + public: + /// Type for file name. + typedef position::filename_type filename_type; + /// Type for line and column numbers. + typedef position::counter_type counter_type; + + /// Construct a location from \a b to \a e. + location (const position& b, const position& e) + : begin (b) + , end (e) + {} + + /// Construct a 0-width location in \a p. + explicit location (const position& p = position ()) + : begin (p) + , end (p) + {} + + /// Construct a 0-width location in \a f, \a l, \a c. + explicit location (filename_type* f, + counter_type l = 1, + counter_type c = 1) + : begin (f, l, c) + , end (f, l, c) + {} + + + /// Initialization. + void initialize (filename_type* f = YY_NULLPTR, + counter_type l = 1, + counter_type c = 1) + { + begin.initialize (f, l, c); + end = begin; + } + + /** \name Line and Column related manipulators + ** \{ */ + public: + /// Reset initial location to final location. + void step () + { + begin = end; + } + + /// Extend the current location to the COUNT next columns. + void columns (counter_type count = 1) + { + end += count; + } + + /// Extend the current location to the COUNT next lines. + void lines (counter_type count = 1) + { + end.lines (count); + } + /** \} */ + + + public: + /// Beginning of the located region. + position begin; + /// End of the located region. + position end; + }; + + /// Join two locations, in place. + inline location& + operator+= (location& res, const location& end) + { + res.end = end.end; + return res; + } + + /// Join two locations. + inline location + operator+ (location res, const location& end) + { + return res += end; + } + + /// Add \a width columns to the end position, in place. + inline location& + operator+= (location& res, location::counter_type width) + { + res.columns (width); + return res; + } + + /// Add \a width columns to the end position. + inline location + operator+ (location res, location::counter_type width) + { + return res += width; + } + + /// Subtract \a width columns to the end position, in place. + inline location& + operator-= (location& res, location::counter_type width) + { + return res += -width; + } + + /// Subtract \a width columns to the end position. + inline location + operator- (location res, location::counter_type width) + { + return res -= width; + } + + /** \brief Intercept output stream redirection. + ** \param ostr the destination output stream + ** \param loc a reference to the location to redirect + ** + ** Avoid duplicate information. + */ + template <typename YYChar> + std::basic_ostream<YYChar>& + operator<< (std::basic_ostream<YYChar>& ostr, const location& loc) + { + location::counter_type end_col + = 0 < loc.end.column ? loc.end.column - 1 : 0; + ostr << loc.begin; + if (loc.end.filename + && (!loc.begin.filename + || *loc.begin.filename != *loc.end.filename)) + ostr << '-' << loc.end.filename << ':' << loc.end.line << '.' << end_col; + else if (loc.begin.line < loc.end.line) + ostr << '-' << loc.end.line << '.' << end_col; + else if (loc.begin.column < end_col) + ostr << '-' << end_col; + return ostr; + } + +} // yy + +#endif // !YY_YY_HOME_GRAHAM_DEV_MU_PICO_SDK_TOOLS_PIOASM_GEN_LOCATION_H_INCLUDED diff --git a/circuitpython/ports/raspberrypi/sdk/tools/pioasm/gen/parser.cpp b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/gen/parser.cpp new file mode 100644 index 0000000..c9bd036 --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/gen/parser.cpp @@ -0,0 +1,2208 @@ +// A Bison parser, made by GNU Bison 3.7.2. + +// Skeleton implementation for Bison LALR(1) parsers in C++ + +// Copyright (C) 2002-2015, 2018-2020 Free Software Foundation, Inc. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +// As a special exception, you may create a larger work that contains +// part or all of the Bison parser skeleton and distribute that work +// under terms of your choice, so long as that work isn't itself a +// parser generator using the skeleton or a modified version thereof +// as a parser skeleton. Alternatively, if you modify or redistribute +// the parser skeleton itself, you may (at your option) remove this +// special exception, which will cause the skeleton and the resulting +// Bison output files to be licensed under the GNU General Public +// License without this special exception. + +// This special exception was added by the Free Software Foundation in +// version 2.2 of Bison. + +// DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, +// especially those whose name start with YY_ or yy_. They are +// private implementation details that can be changed or removed. + + + + + +#include "parser.hpp" + + +// Unqualified %code blocks. + + #include "pio_assembler.h" + #ifdef _MSC_VER + #pragma warning(disable : 4244) // possible loss of data (valid warning, but there is a software check / missing cast) + #endif + + + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> // FIXME: INFRINGES ON USER NAME SPACE. +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + + +// Whether we are compiled with exception support. +#ifndef YY_EXCEPTIONS +# if defined __GNUC__ && !defined __EXCEPTIONS +# define YY_EXCEPTIONS 0 +# else +# define YY_EXCEPTIONS 1 +# endif +#endif + +#define YYRHSLOC(Rhs, K) ((Rhs)[K].location) +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +# ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (N) \ + { \ + (Current).begin = YYRHSLOC (Rhs, 1).begin; \ + (Current).end = YYRHSLOC (Rhs, N).end; \ + } \ + else \ + { \ + (Current).begin = (Current).end = YYRHSLOC (Rhs, 0).end; \ + } \ + while (false) +# endif + + +// Enable debugging if requested. +#if YYDEBUG + +// A pseudo ostream that takes yydebug_ into account. +# define YYCDEBUG if (yydebug_) (*yycdebug_) + +# define YY_SYMBOL_PRINT(Title, Symbol) \ + do { \ + if (yydebug_) \ + { \ + *yycdebug_ << Title << ' '; \ + yy_print_ (*yycdebug_, Symbol); \ + *yycdebug_ << '\n'; \ + } \ + } while (false) + +# define YY_REDUCE_PRINT(Rule) \ + do { \ + if (yydebug_) \ + yy_reduce_print_ (Rule); \ + } while (false) + +# define YY_STACK_PRINT() \ + do { \ + if (yydebug_) \ + yy_stack_print_ (); \ + } while (false) + +#else // !YYDEBUG + +# define YYCDEBUG if (false) std::cerr +# define YY_SYMBOL_PRINT(Title, Symbol) YYUSE (Symbol) +# define YY_REDUCE_PRINT(Rule) static_cast<void> (0) +# define YY_STACK_PRINT() static_cast<void> (0) + +#endif // !YYDEBUG + +#define yyerrok (yyerrstatus_ = 0) +#define yyclearin (yyla.clear ()) + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab +#define YYRECOVERING() (!!yyerrstatus_) + +namespace yy { + + /// Build a parser object. + parser::parser (pio_assembler& pioasm_yyarg) +#if YYDEBUG + : yydebug_ (false), + yycdebug_ (&std::cerr), +#else + : +#endif + yy_lac_established_ (false), + pioasm (pioasm_yyarg) + {} + + parser::~parser () + {} + + parser::syntax_error::~syntax_error () YY_NOEXCEPT YY_NOTHROW + {} + + /*---------------. + | symbol kinds. | + `---------------*/ + + + + // by_state. + parser::by_state::by_state () YY_NOEXCEPT + : state (empty_state) + {} + + parser::by_state::by_state (const by_state& that) YY_NOEXCEPT + : state (that.state) + {} + + void + parser::by_state::clear () YY_NOEXCEPT + { + state = empty_state; + } + + void + parser::by_state::move (by_state& that) + { + state = that.state; + that.clear (); + } + + parser::by_state::by_state (state_type s) YY_NOEXCEPT + : state (s) + {} + + parser::symbol_kind_type + parser::by_state::kind () const YY_NOEXCEPT + { + if (state == empty_state) + return symbol_kind::S_YYEMPTY; + else + return YY_CAST (symbol_kind_type, yystos_[+state]); + } + + parser::stack_symbol_type::stack_symbol_type () + {} + + parser::stack_symbol_type::stack_symbol_type (YY_RVREF (stack_symbol_type) that) + : super_type (YY_MOVE (that.state), YY_MOVE (that.location)) + { + switch (that.kind ()) + { + case symbol_kind::S_if_full: // if_full + case symbol_kind::S_if_empty: // if_empty + case symbol_kind::S_blocking: // blocking + value.YY_MOVE_OR_COPY< bool > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_condition: // condition + value.YY_MOVE_OR_COPY< enum condition > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_in_source: // in_source + case symbol_kind::S_out_target: // out_target + case symbol_kind::S_set_target: // set_target + value.YY_MOVE_OR_COPY< enum in_out_set > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_irq_modifiers: // irq_modifiers + value.YY_MOVE_OR_COPY< enum irq > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_mov_target: // mov_target + case symbol_kind::S_mov_source: // mov_source + value.YY_MOVE_OR_COPY< enum mov > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_mov_op: // mov_op + value.YY_MOVE_OR_COPY< enum mov_op > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_INT: // "integer" + value.YY_MOVE_OR_COPY< int > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_instruction: // instruction + case symbol_kind::S_base_instruction: // base_instruction + value.YY_MOVE_OR_COPY< std::shared_ptr<instruction> > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_value: // value + case symbol_kind::S_expression: // expression + case symbol_kind::S_delay: // delay + case symbol_kind::S_sideset: // sideset + value.YY_MOVE_OR_COPY< std::shared_ptr<resolvable> > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_label_decl: // label_decl + case symbol_kind::S_symbol_def: // symbol_def + value.YY_MOVE_OR_COPY< std::shared_ptr<symbol> > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_wait_source: // wait_source + value.YY_MOVE_OR_COPY< std::shared_ptr<wait_source> > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_ID: // "identifier" + case symbol_kind::S_STRING: // "string" + case symbol_kind::S_NON_WS: // "text" + case symbol_kind::S_CODE_BLOCK_START: // "code block" + case symbol_kind::S_CODE_BLOCK_CONTENTS: // "%}" + case symbol_kind::S_UNKNOWN_DIRECTIVE: // UNKNOWN_DIRECTIVE + value.YY_MOVE_OR_COPY< std::string > (YY_MOVE (that.value)); + break; + + default: + break; + } + +#if 201103L <= YY_CPLUSPLUS + // that is emptied. + that.state = empty_state; +#endif + } + + parser::stack_symbol_type::stack_symbol_type (state_type s, YY_MOVE_REF (symbol_type) that) + : super_type (s, YY_MOVE (that.location)) + { + switch (that.kind ()) + { + case symbol_kind::S_if_full: // if_full + case symbol_kind::S_if_empty: // if_empty + case symbol_kind::S_blocking: // blocking + value.move< bool > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_condition: // condition + value.move< enum condition > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_in_source: // in_source + case symbol_kind::S_out_target: // out_target + case symbol_kind::S_set_target: // set_target + value.move< enum in_out_set > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_irq_modifiers: // irq_modifiers + value.move< enum irq > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_mov_target: // mov_target + case symbol_kind::S_mov_source: // mov_source + value.move< enum mov > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_mov_op: // mov_op + value.move< enum mov_op > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_INT: // "integer" + value.move< int > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_instruction: // instruction + case symbol_kind::S_base_instruction: // base_instruction + value.move< std::shared_ptr<instruction> > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_value: // value + case symbol_kind::S_expression: // expression + case symbol_kind::S_delay: // delay + case symbol_kind::S_sideset: // sideset + value.move< std::shared_ptr<resolvable> > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_label_decl: // label_decl + case symbol_kind::S_symbol_def: // symbol_def + value.move< std::shared_ptr<symbol> > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_wait_source: // wait_source + value.move< std::shared_ptr<wait_source> > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_ID: // "identifier" + case symbol_kind::S_STRING: // "string" + case symbol_kind::S_NON_WS: // "text" + case symbol_kind::S_CODE_BLOCK_START: // "code block" + case symbol_kind::S_CODE_BLOCK_CONTENTS: // "%}" + case symbol_kind::S_UNKNOWN_DIRECTIVE: // UNKNOWN_DIRECTIVE + value.move< std::string > (YY_MOVE (that.value)); + break; + + default: + break; + } + + // that is emptied. + that.kind_ = symbol_kind::S_YYEMPTY; + } + +#if YY_CPLUSPLUS < 201103L + parser::stack_symbol_type& + parser::stack_symbol_type::operator= (const stack_symbol_type& that) + { + state = that.state; + switch (that.kind ()) + { + case symbol_kind::S_if_full: // if_full + case symbol_kind::S_if_empty: // if_empty + case symbol_kind::S_blocking: // blocking + value.copy< bool > (that.value); + break; + + case symbol_kind::S_condition: // condition + value.copy< enum condition > (that.value); + break; + + case symbol_kind::S_in_source: // in_source + case symbol_kind::S_out_target: // out_target + case symbol_kind::S_set_target: // set_target + value.copy< enum in_out_set > (that.value); + break; + + case symbol_kind::S_irq_modifiers: // irq_modifiers + value.copy< enum irq > (that.value); + break; + + case symbol_kind::S_mov_target: // mov_target + case symbol_kind::S_mov_source: // mov_source + value.copy< enum mov > (that.value); + break; + + case symbol_kind::S_mov_op: // mov_op + value.copy< enum mov_op > (that.value); + break; + + case symbol_kind::S_INT: // "integer" + value.copy< int > (that.value); + break; + + case symbol_kind::S_instruction: // instruction + case symbol_kind::S_base_instruction: // base_instruction + value.copy< std::shared_ptr<instruction> > (that.value); + break; + + case symbol_kind::S_value: // value + case symbol_kind::S_expression: // expression + case symbol_kind::S_delay: // delay + case symbol_kind::S_sideset: // sideset + value.copy< std::shared_ptr<resolvable> > (that.value); + break; + + case symbol_kind::S_label_decl: // label_decl + case symbol_kind::S_symbol_def: // symbol_def + value.copy< std::shared_ptr<symbol> > (that.value); + break; + + case symbol_kind::S_wait_source: // wait_source + value.copy< std::shared_ptr<wait_source> > (that.value); + break; + + case symbol_kind::S_ID: // "identifier" + case symbol_kind::S_STRING: // "string" + case symbol_kind::S_NON_WS: // "text" + case symbol_kind::S_CODE_BLOCK_START: // "code block" + case symbol_kind::S_CODE_BLOCK_CONTENTS: // "%}" + case symbol_kind::S_UNKNOWN_DIRECTIVE: // UNKNOWN_DIRECTIVE + value.copy< std::string > (that.value); + break; + + default: + break; + } + + location = that.location; + return *this; + } + + parser::stack_symbol_type& + parser::stack_symbol_type::operator= (stack_symbol_type& that) + { + state = that.state; + switch (that.kind ()) + { + case symbol_kind::S_if_full: // if_full + case symbol_kind::S_if_empty: // if_empty + case symbol_kind::S_blocking: // blocking + value.move< bool > (that.value); + break; + + case symbol_kind::S_condition: // condition + value.move< enum condition > (that.value); + break; + + case symbol_kind::S_in_source: // in_source + case symbol_kind::S_out_target: // out_target + case symbol_kind::S_set_target: // set_target + value.move< enum in_out_set > (that.value); + break; + + case symbol_kind::S_irq_modifiers: // irq_modifiers + value.move< enum irq > (that.value); + break; + + case symbol_kind::S_mov_target: // mov_target + case symbol_kind::S_mov_source: // mov_source + value.move< enum mov > (that.value); + break; + + case symbol_kind::S_mov_op: // mov_op + value.move< enum mov_op > (that.value); + break; + + case symbol_kind::S_INT: // "integer" + value.move< int > (that.value); + break; + + case symbol_kind::S_instruction: // instruction + case symbol_kind::S_base_instruction: // base_instruction + value.move< std::shared_ptr<instruction> > (that.value); + break; + + case symbol_kind::S_value: // value + case symbol_kind::S_expression: // expression + case symbol_kind::S_delay: // delay + case symbol_kind::S_sideset: // sideset + value.move< std::shared_ptr<resolvable> > (that.value); + break; + + case symbol_kind::S_label_decl: // label_decl + case symbol_kind::S_symbol_def: // symbol_def + value.move< std::shared_ptr<symbol> > (that.value); + break; + + case symbol_kind::S_wait_source: // wait_source + value.move< std::shared_ptr<wait_source> > (that.value); + break; + + case symbol_kind::S_ID: // "identifier" + case symbol_kind::S_STRING: // "string" + case symbol_kind::S_NON_WS: // "text" + case symbol_kind::S_CODE_BLOCK_START: // "code block" + case symbol_kind::S_CODE_BLOCK_CONTENTS: // "%}" + case symbol_kind::S_UNKNOWN_DIRECTIVE: // UNKNOWN_DIRECTIVE + value.move< std::string > (that.value); + break; + + default: + break; + } + + location = that.location; + // that is emptied. + that.state = empty_state; + return *this; + } +#endif + + template <typename Base> + void + parser::yy_destroy_ (const char* yymsg, basic_symbol<Base>& yysym) const + { + if (yymsg) + YY_SYMBOL_PRINT (yymsg, yysym); + } + +#if YYDEBUG + template <typename Base> + void + parser::yy_print_ (std::ostream& yyo, const basic_symbol<Base>& yysym) const + { + std::ostream& yyoutput = yyo; + YYUSE (yyoutput); + if (yysym.empty ()) + yyo << "empty symbol"; + else + { + symbol_kind_type yykind = yysym.kind (); + yyo << (yykind < YYNTOKENS ? "token" : "nterm") + << ' ' << yysym.name () << " (" + << yysym.location << ": "; + switch (yykind) + { + case symbol_kind::S_ID: // "identifier" + { yyo << "..."; } + break; + + case symbol_kind::S_STRING: // "string" + { yyo << "..."; } + break; + + case symbol_kind::S_NON_WS: // "text" + { yyo << "..."; } + break; + + case symbol_kind::S_CODE_BLOCK_START: // "code block" + { yyo << "..."; } + break; + + case symbol_kind::S_CODE_BLOCK_CONTENTS: // "%}" + { yyo << "..."; } + break; + + case symbol_kind::S_UNKNOWN_DIRECTIVE: // UNKNOWN_DIRECTIVE + { yyo << "..."; } + break; + + case symbol_kind::S_INT: // "integer" + { yyo << "..."; } + break; + + case symbol_kind::S_label_decl: // label_decl + { yyo << "..."; } + break; + + case symbol_kind::S_value: // value + { yyo << "..."; } + break; + + case symbol_kind::S_expression: // expression + { yyo << "..."; } + break; + + case symbol_kind::S_instruction: // instruction + { yyo << "..."; } + break; + + case symbol_kind::S_base_instruction: // base_instruction + { yyo << "..."; } + break; + + case symbol_kind::S_delay: // delay + { yyo << "..."; } + break; + + case symbol_kind::S_sideset: // sideset + { yyo << "..."; } + break; + + case symbol_kind::S_condition: // condition + { yyo << "..."; } + break; + + case symbol_kind::S_wait_source: // wait_source + { yyo << "..."; } + break; + + case symbol_kind::S_in_source: // in_source + { yyo << "..."; } + break; + + case symbol_kind::S_out_target: // out_target + { yyo << "..."; } + break; + + case symbol_kind::S_mov_target: // mov_target + { yyo << "..."; } + break; + + case symbol_kind::S_mov_source: // mov_source + { yyo << "..."; } + break; + + case symbol_kind::S_mov_op: // mov_op + { yyo << "..."; } + break; + + case symbol_kind::S_set_target: // set_target + { yyo << "..."; } + break; + + case symbol_kind::S_if_full: // if_full + { yyo << "..."; } + break; + + case symbol_kind::S_if_empty: // if_empty + { yyo << "..."; } + break; + + case symbol_kind::S_blocking: // blocking + { yyo << "..."; } + break; + + case symbol_kind::S_irq_modifiers: // irq_modifiers + { yyo << "..."; } + break; + + case symbol_kind::S_symbol_def: // symbol_def + { yyo << "..."; } + break; + + default: + break; + } + yyo << ')'; + } + } +#endif + + void + parser::yypush_ (const char* m, YY_MOVE_REF (stack_symbol_type) sym) + { + if (m) + YY_SYMBOL_PRINT (m, sym); + yystack_.push (YY_MOVE (sym)); + } + + void + parser::yypush_ (const char* m, state_type s, YY_MOVE_REF (symbol_type) sym) + { +#if 201103L <= YY_CPLUSPLUS + yypush_ (m, stack_symbol_type (s, std::move (sym))); +#else + stack_symbol_type ss (s, sym); + yypush_ (m, ss); +#endif + } + + void + parser::yypop_ (int n) + { + yystack_.pop (n); + } + +#if YYDEBUG + std::ostream& + parser::debug_stream () const + { + return *yycdebug_; + } + + void + parser::set_debug_stream (std::ostream& o) + { + yycdebug_ = &o; + } + + + parser::debug_level_type + parser::debug_level () const + { + return yydebug_; + } + + void + parser::set_debug_level (debug_level_type l) + { + yydebug_ = l; + } +#endif // YYDEBUG + + parser::state_type + parser::yy_lr_goto_state_ (state_type yystate, int yysym) + { + int yyr = yypgoto_[yysym - YYNTOKENS] + yystate; + if (0 <= yyr && yyr <= yylast_ && yycheck_[yyr] == yystate) + return yytable_[yyr]; + else + return yydefgoto_[yysym - YYNTOKENS]; + } + + bool + parser::yy_pact_value_is_default_ (int yyvalue) + { + return yyvalue == yypact_ninf_; + } + + bool + parser::yy_table_value_is_error_ (int yyvalue) + { + return yyvalue == yytable_ninf_; + } + + int + parser::operator() () + { + return parse (); + } + + int + parser::parse () + { + int yyn; + /// Length of the RHS of the rule being reduced. + int yylen = 0; + + // Error handling. + int yynerrs_ = 0; + int yyerrstatus_ = 0; + + /// The lookahead symbol. + symbol_type yyla; + + /// The locations where the error started and ended. + stack_symbol_type yyerror_range[3]; + + /// The return value of parse (). + int yyresult; + + /// Discard the LAC context in case there still is one left from a + /// previous invocation. + yy_lac_discard_ ("init"); + +#if YY_EXCEPTIONS + try +#endif // YY_EXCEPTIONS + { + YYCDEBUG << "Starting parse\n"; + + + /* Initialize the stack. The initial state will be set in + yynewstate, since the latter expects the semantical and the + location values to have been already stored, initialize these + stacks with a primary value. */ + yystack_.clear (); + yypush_ (YY_NULLPTR, 0, YY_MOVE (yyla)); + + /*-----------------------------------------------. + | yynewstate -- push a new symbol on the stack. | + `-----------------------------------------------*/ + yynewstate: + YYCDEBUG << "Entering state " << int (yystack_[0].state) << '\n'; + YY_STACK_PRINT (); + + // Accept? + if (yystack_[0].state == yyfinal_) + YYACCEPT; + + goto yybackup; + + + /*-----------. + | yybackup. | + `-----------*/ + yybackup: + // Try to take a decision without lookahead. + yyn = yypact_[+yystack_[0].state]; + if (yy_pact_value_is_default_ (yyn)) + goto yydefault; + + // Read a lookahead token. + if (yyla.empty ()) + { + YYCDEBUG << "Reading a token\n"; +#if YY_EXCEPTIONS + try +#endif // YY_EXCEPTIONS + { + symbol_type yylookahead (yylex (pioasm)); + yyla.move (yylookahead); + } +#if YY_EXCEPTIONS + catch (const syntax_error& yyexc) + { + YYCDEBUG << "Caught exception: " << yyexc.what() << '\n'; + error (yyexc); + goto yyerrlab1; + } +#endif // YY_EXCEPTIONS + } + YY_SYMBOL_PRINT ("Next token is", yyla); + + if (yyla.kind () == symbol_kind::S_YYerror) + { + // The scanner already issued an error message, process directly + // to error recovery. But do not keep the error token as + // lookahead, it is too special and may lead us to an endless + // loop in error recovery. */ + yyla.kind_ = symbol_kind::S_YYUNDEF; + goto yyerrlab1; + } + + /* If the proper action on seeing token YYLA.TYPE is to reduce or + to detect an error, take that action. */ + yyn += yyla.kind (); + if (yyn < 0 || yylast_ < yyn || yycheck_[yyn] != yyla.kind ()) + { + if (!yy_lac_establish_ (yyla.kind ())) + goto yyerrlab; + goto yydefault; + } + + // Reduce or error. + yyn = yytable_[yyn]; + if (yyn <= 0) + { + if (yy_table_value_is_error_ (yyn)) + goto yyerrlab; + if (!yy_lac_establish_ (yyla.kind ())) + goto yyerrlab; + + yyn = -yyn; + goto yyreduce; + } + + // Count tokens shifted since error; after three, turn off error status. + if (yyerrstatus_) + --yyerrstatus_; + + // Shift the lookahead token. + yypush_ ("Shifting", state_type (yyn), YY_MOVE (yyla)); + yy_lac_discard_ ("shift"); + goto yynewstate; + + + /*-----------------------------------------------------------. + | yydefault -- do the default action for the current state. | + `-----------------------------------------------------------*/ + yydefault: + yyn = yydefact_[+yystack_[0].state]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + + /*-----------------------------. + | yyreduce -- do a reduction. | + `-----------------------------*/ + yyreduce: + yylen = yyr2_[yyn]; + { + stack_symbol_type yylhs; + yylhs.state = yy_lr_goto_state_ (yystack_[yylen].state, yyr1_[yyn]); + /* Variants are always initialized to an empty instance of the + correct type. The default '$$ = $1' action is NOT applied + when using variants. */ + switch (yyr1_[yyn]) + { + case symbol_kind::S_if_full: // if_full + case symbol_kind::S_if_empty: // if_empty + case symbol_kind::S_blocking: // blocking + yylhs.value.emplace< bool > (); + break; + + case symbol_kind::S_condition: // condition + yylhs.value.emplace< enum condition > (); + break; + + case symbol_kind::S_in_source: // in_source + case symbol_kind::S_out_target: // out_target + case symbol_kind::S_set_target: // set_target + yylhs.value.emplace< enum in_out_set > (); + break; + + case symbol_kind::S_irq_modifiers: // irq_modifiers + yylhs.value.emplace< enum irq > (); + break; + + case symbol_kind::S_mov_target: // mov_target + case symbol_kind::S_mov_source: // mov_source + yylhs.value.emplace< enum mov > (); + break; + + case symbol_kind::S_mov_op: // mov_op + yylhs.value.emplace< enum mov_op > (); + break; + + case symbol_kind::S_INT: // "integer" + yylhs.value.emplace< int > (); + break; + + case symbol_kind::S_instruction: // instruction + case symbol_kind::S_base_instruction: // base_instruction + yylhs.value.emplace< std::shared_ptr<instruction> > (); + break; + + case symbol_kind::S_value: // value + case symbol_kind::S_expression: // expression + case symbol_kind::S_delay: // delay + case symbol_kind::S_sideset: // sideset + yylhs.value.emplace< std::shared_ptr<resolvable> > (); + break; + + case symbol_kind::S_label_decl: // label_decl + case symbol_kind::S_symbol_def: // symbol_def + yylhs.value.emplace< std::shared_ptr<symbol> > (); + break; + + case symbol_kind::S_wait_source: // wait_source + yylhs.value.emplace< std::shared_ptr<wait_source> > (); + break; + + case symbol_kind::S_ID: // "identifier" + case symbol_kind::S_STRING: // "string" + case symbol_kind::S_NON_WS: // "text" + case symbol_kind::S_CODE_BLOCK_START: // "code block" + case symbol_kind::S_CODE_BLOCK_CONTENTS: // "%}" + case symbol_kind::S_UNKNOWN_DIRECTIVE: // UNKNOWN_DIRECTIVE + yylhs.value.emplace< std::string > (); + break; + + default: + break; + } + + + // Default location. + { + stack_type::slice range (yystack_, yylen); + YYLLOC_DEFAULT (yylhs.location, range, yylen); + yyerror_range[1].location = yylhs.location; + } + + // Perform the reduction. + YY_REDUCE_PRINT (yyn); +#if YY_EXCEPTIONS + try +#endif // YY_EXCEPTIONS + { + switch (yyn) + { + case 2: // file: lines "end of file" + { if (pioasm.error_count || pioasm.write_output()) YYABORT; } + break; + + case 5: // line: ".program" "identifier" + { if (!pioasm.add_program(yylhs.location, yystack_[0].value.as < std::string > ())) { std::stringstream msg; msg << "program " << yystack_[0].value.as < std::string > () << " already exists"; error(yylhs.location, msg.str()); abort(); } } + break; + + case 7: // line: instruction + { pioasm.get_current_program(yystack_[0].location, "instruction").add_instruction(yystack_[0].value.as < std::shared_ptr<instruction> > ()); } + break; + + case 8: // line: label_decl instruction + { auto &p = pioasm.get_current_program(yystack_[0].location, "instruction"); p.add_label(yystack_[1].value.as < std::shared_ptr<symbol> > ()); p.add_instruction(yystack_[0].value.as < std::shared_ptr<instruction> > ()); } + break; + + case 9: // line: label_decl + { pioasm.get_current_program(yystack_[0].location, "label").add_label(yystack_[0].value.as < std::shared_ptr<symbol> > ()); } + break; + + case 12: // line: error + { if (pioasm.error_count > 6) { std::cerr << "\ntoo many errors; aborting.\n"; YYABORT; } } + break; + + case 13: // code_block: "code block" "%}" + { std::string of = yystack_[1].value.as < std::string > (); if (of.empty()) of = output_format::default_name; pioasm.get_current_program(yylhs.location, "code block", false, false).add_code_block( code_block(yylhs.location, of, yystack_[0].value.as < std::string > ())); } + break; + + case 14: // label_decl: symbol_def ":" + { yystack_[1].value.as < std::shared_ptr<symbol> > ()->is_label = true; yylhs.value.as < std::shared_ptr<symbol> > () = yystack_[1].value.as < std::shared_ptr<symbol> > (); } + break; + + case 15: // directive: ".define" symbol_def expression + { yystack_[1].value.as < std::shared_ptr<symbol> > ()->is_label = false; yystack_[1].value.as < std::shared_ptr<symbol> > ()->value = yystack_[0].value.as < std::shared_ptr<resolvable> > (); pioasm.get_current_program(yystack_[2].location, ".define", false, false).add_symbol(yystack_[1].value.as < std::shared_ptr<symbol> > ()); } + break; + + case 16: // directive: ".origin" value + { pioasm.get_current_program(yystack_[1].location, ".origin", true).set_origin(yylhs.location, yystack_[0].value.as < std::shared_ptr<resolvable> > ()); } + break; + + case 17: // directive: ".side_set" value "opt" "pindirs" + { pioasm.get_current_program(yystack_[3].location, ".side_set", true).set_sideset(yylhs.location, yystack_[2].value.as < std::shared_ptr<resolvable> > (), true, true); } + break; + + case 18: // directive: ".side_set" value "opt" + { pioasm.get_current_program(yystack_[2].location, ".side_set", true).set_sideset(yylhs.location, yystack_[1].value.as < std::shared_ptr<resolvable> > (), true, false); } + break; + + case 19: // directive: ".side_set" value "pindirs" + { pioasm.get_current_program(yystack_[2].location, ".side_set", true).set_sideset(yylhs.location, yystack_[1].value.as < std::shared_ptr<resolvable> > (), false, true); } + break; + + case 20: // directive: ".side_set" value + { pioasm.get_current_program(yystack_[1].location, ".side_set", true).set_sideset(yylhs.location, yystack_[0].value.as < std::shared_ptr<resolvable> > (), false, false); } + break; + + case 21: // directive: ".wrap_target" + { pioasm.get_current_program(yystack_[0].location, ".wrap_target").set_wrap_target(yylhs.location); } + break; + + case 22: // directive: ".wrap" + { pioasm.get_current_program(yystack_[0].location, ".wrap").set_wrap(yylhs.location); } + break; + + case 23: // directive: ".word" value + { pioasm.get_current_program(yystack_[1].location, "instruction").add_instruction(std::shared_ptr<instruction>(new instr_word(yylhs.location, yystack_[0].value.as < std::shared_ptr<resolvable> > ()))); } + break; + + case 24: // directive: ".lang_opt" "text" "text" "=" "integer" + { pioasm.get_current_program(yystack_[4].location, ".lang_opt").add_lang_opt(yystack_[3].value.as < std::string > (), yystack_[2].value.as < std::string > (), std::to_string(yystack_[0].value.as < int > ())); } + break; + + case 25: // directive: ".lang_opt" "text" "text" "=" "string" + { pioasm.get_current_program(yystack_[4].location, ".lang_opt").add_lang_opt(yystack_[3].value.as < std::string > (), yystack_[2].value.as < std::string > (), yystack_[0].value.as < std::string > ()); } + break; + + case 26: // directive: ".lang_opt" "text" "text" "=" "text" + { pioasm.get_current_program(yystack_[4].location, ".lang_opt").add_lang_opt(yystack_[3].value.as < std::string > (), yystack_[2].value.as < std::string > (), yystack_[0].value.as < std::string > ()); } + break; + + case 27: // directive: ".lang_opt" error + { error(yylhs.location, "expected format is .lang_opt language option_name = option_value"); } + break; + + case 28: // directive: UNKNOWN_DIRECTIVE + { std::stringstream msg; msg << "unknown directive " << yystack_[0].value.as < std::string > (); throw syntax_error(yylhs.location, msg.str()); } + break; + + case 29: // value: "integer" + { yylhs.value.as < std::shared_ptr<resolvable> > () = resolvable_int(yylhs.location, yystack_[0].value.as < int > ()); } + break; + + case 30: // value: "identifier" + { yylhs.value.as < std::shared_ptr<resolvable> > () = std::shared_ptr<resolvable>(new name_ref(yylhs.location, yystack_[0].value.as < std::string > ())); } + break; + + case 31: // value: "(" expression ")" + { yylhs.value.as < std::shared_ptr<resolvable> > () = yystack_[1].value.as < std::shared_ptr<resolvable> > (); } + break; + + case 32: // expression: value + { yylhs.value.as < std::shared_ptr<resolvable> > () = yystack_[0].value.as < std::shared_ptr<resolvable> > (); } + break; + + case 33: // expression: expression "+" expression + { yylhs.value.as < std::shared_ptr<resolvable> > () = std::shared_ptr<binary_operation>(new binary_operation(yylhs.location, binary_operation::add, yystack_[2].value.as < std::shared_ptr<resolvable> > (), yystack_[0].value.as < std::shared_ptr<resolvable> > ())); } + break; + + case 34: // expression: expression "-" expression + { yylhs.value.as < std::shared_ptr<resolvable> > () = std::shared_ptr<binary_operation>(new binary_operation(yylhs.location, binary_operation::subtract, yystack_[2].value.as < std::shared_ptr<resolvable> > (), yystack_[0].value.as < std::shared_ptr<resolvable> > ())); } + break; + + case 35: // expression: expression "*" expression + { yylhs.value.as < std::shared_ptr<resolvable> > () = std::shared_ptr<binary_operation>(new binary_operation(yylhs.location, binary_operation::multiply, yystack_[2].value.as < std::shared_ptr<resolvable> > (), yystack_[0].value.as < std::shared_ptr<resolvable> > ())); } + break; + + case 36: // expression: expression "/" expression + { yylhs.value.as < std::shared_ptr<resolvable> > () = std::shared_ptr<binary_operation>(new binary_operation(yylhs.location, binary_operation::divide, yystack_[2].value.as < std::shared_ptr<resolvable> > (), yystack_[0].value.as < std::shared_ptr<resolvable> > ())); } + break; + + case 37: // expression: expression "|" expression + { yylhs.value.as < std::shared_ptr<resolvable> > () = std::shared_ptr<binary_operation>(new binary_operation(yylhs.location, binary_operation::or_, yystack_[2].value.as < std::shared_ptr<resolvable> > (), yystack_[0].value.as < std::shared_ptr<resolvable> > ())); } + break; + + case 38: // expression: expression "&" expression + { yylhs.value.as < std::shared_ptr<resolvable> > () = std::shared_ptr<binary_operation>(new binary_operation(yylhs.location, binary_operation::and_, yystack_[2].value.as < std::shared_ptr<resolvable> > (), yystack_[0].value.as < std::shared_ptr<resolvable> > ())); } + break; + + case 39: // expression: expression "^" expression + { yylhs.value.as < std::shared_ptr<resolvable> > () = std::shared_ptr<binary_operation>(new binary_operation(yylhs.location, binary_operation::xor_, yystack_[2].value.as < std::shared_ptr<resolvable> > (), yystack_[0].value.as < std::shared_ptr<resolvable> > ())); } + break; + + case 40: // expression: "-" expression + { yylhs.value.as < std::shared_ptr<resolvable> > () = std::shared_ptr<unary_operation>(new unary_operation(yylhs.location, unary_operation::negate, yystack_[0].value.as < std::shared_ptr<resolvable> > ())); } + break; + + case 41: // expression: "::" expression + { yylhs.value.as < std::shared_ptr<resolvable> > () = std::shared_ptr<unary_operation>(new unary_operation(yylhs.location, unary_operation::reverse, yystack_[0].value.as < std::shared_ptr<resolvable> > ())); } + break; + + case 42: // instruction: base_instruction sideset delay + { yylhs.value.as < std::shared_ptr<instruction> > () = yystack_[2].value.as < std::shared_ptr<instruction> > (); yylhs.value.as < std::shared_ptr<instruction> > ()->sideset = yystack_[1].value.as < std::shared_ptr<resolvable> > (); yylhs.value.as < std::shared_ptr<instruction> > ()->delay = yystack_[0].value.as < std::shared_ptr<resolvable> > (); } + break; + + case 43: // instruction: base_instruction delay sideset + { yylhs.value.as < std::shared_ptr<instruction> > () = yystack_[2].value.as < std::shared_ptr<instruction> > (); yylhs.value.as < std::shared_ptr<instruction> > ()->delay = yystack_[1].value.as < std::shared_ptr<resolvable> > (); yylhs.value.as < std::shared_ptr<instruction> > ()->sideset = yystack_[0].value.as < std::shared_ptr<resolvable> > (); } + break; + + case 44: // instruction: base_instruction sideset + { yylhs.value.as < std::shared_ptr<instruction> > () = yystack_[1].value.as < std::shared_ptr<instruction> > (); yylhs.value.as < std::shared_ptr<instruction> > ()->sideset = yystack_[0].value.as < std::shared_ptr<resolvable> > (); yylhs.value.as < std::shared_ptr<instruction> > ()->delay = resolvable_int(yylhs.location, 0); } + break; + + case 45: // instruction: base_instruction delay + { yylhs.value.as < std::shared_ptr<instruction> > () = yystack_[1].value.as < std::shared_ptr<instruction> > (); yylhs.value.as < std::shared_ptr<instruction> > ()->delay = yystack_[0].value.as < std::shared_ptr<resolvable> > (); } + break; + + case 46: // instruction: base_instruction + { yylhs.value.as < std::shared_ptr<instruction> > () = yystack_[0].value.as < std::shared_ptr<instruction> > (); yylhs.value.as < std::shared_ptr<instruction> > ()->delay = resolvable_int(yylhs.location, 0); } + break; + + case 47: // base_instruction: "nop" + { yylhs.value.as < std::shared_ptr<instruction> > () = std::shared_ptr<instruction>(new instr_nop(yylhs.location)); } + break; + + case 48: // base_instruction: "jmp" condition comma expression + { yylhs.value.as < std::shared_ptr<instruction> > () = std::shared_ptr<instruction>(new instr_jmp(yylhs.location, yystack_[2].value.as < enum condition > (), yystack_[0].value.as < std::shared_ptr<resolvable> > ())); } + break; + + case 49: // base_instruction: "wait" value wait_source + { yylhs.value.as < std::shared_ptr<instruction> > () = std::shared_ptr<instruction>(new instr_wait(yylhs.location, yystack_[1].value.as < std::shared_ptr<resolvable> > (), yystack_[0].value.as < std::shared_ptr<wait_source> > ())); } + break; + + case 50: // base_instruction: "wait" value "," value + { std::stringstream msg; location l; l.begin = yystack_[2].location.end; l.end = yystack_[1].location.end; msg << "expected irq, gpio or pin after the polarity value and before the \",\""; throw yy::parser::syntax_error(l, msg.str()); } + break; + + case 51: // base_instruction: "wait" wait_source + { yylhs.value.as < std::shared_ptr<instruction> > () = std::shared_ptr<instruction>(new instr_wait(yylhs.location, resolvable_int(yylhs.location, 1), yystack_[0].value.as < std::shared_ptr<wait_source> > ())); } + break; + + case 52: // base_instruction: "in" in_source comma value + { yylhs.value.as < std::shared_ptr<instruction> > () = std::shared_ptr<instruction>(new instr_in(yylhs.location, yystack_[2].value.as < enum in_out_set > (), yystack_[0].value.as < std::shared_ptr<resolvable> > ())); } + break; + + case 53: // base_instruction: "out" out_target comma value + { yylhs.value.as < std::shared_ptr<instruction> > () = std::shared_ptr<instruction>(new instr_out(yylhs.location, yystack_[2].value.as < enum in_out_set > (), yystack_[0].value.as < std::shared_ptr<resolvable> > ())); } + break; + + case 54: // base_instruction: "push" if_full blocking + { yylhs.value.as < std::shared_ptr<instruction> > () = std::shared_ptr<instruction>(new instr_push(yylhs.location, yystack_[1].value.as < bool > (), yystack_[0].value.as < bool > ())); } + break; + + case 55: // base_instruction: "pull" if_empty blocking + { yylhs.value.as < std::shared_ptr<instruction> > () = std::shared_ptr<instruction>(new instr_pull(yylhs.location, yystack_[1].value.as < bool > (), yystack_[0].value.as < bool > ())); } + break; + + case 56: // base_instruction: "mov" mov_target comma mov_op mov_source + { yylhs.value.as < std::shared_ptr<instruction> > () = std::shared_ptr<instruction>(new instr_mov(yylhs.location, yystack_[3].value.as < enum mov > (), yystack_[0].value.as < enum mov > (), yystack_[1].value.as < enum mov_op > ())); } + break; + + case 57: // base_instruction: "irq" irq_modifiers value "rel" + { yylhs.value.as < std::shared_ptr<instruction> > () = std::shared_ptr<instruction>(new instr_irq(yylhs.location, yystack_[2].value.as < enum irq > (), yystack_[1].value.as < std::shared_ptr<resolvable> > (), true)); } + break; + + case 58: // base_instruction: "irq" irq_modifiers value + { yylhs.value.as < std::shared_ptr<instruction> > () = std::shared_ptr<instruction>(new instr_irq(yylhs.location, yystack_[1].value.as < enum irq > (), yystack_[0].value.as < std::shared_ptr<resolvable> > ())); } + break; + + case 59: // base_instruction: "set" set_target comma value + { yylhs.value.as < std::shared_ptr<instruction> > () = std::shared_ptr<instruction>(new instr_set(yylhs.location, yystack_[2].value.as < enum in_out_set > (), yystack_[0].value.as < std::shared_ptr<resolvable> > ())); } + break; + + case 60: // delay: "[" expression "]" + { yylhs.value.as < std::shared_ptr<resolvable> > () = yystack_[1].value.as < std::shared_ptr<resolvable> > (); } + break; + + case 61: // sideset: "side" value + { yylhs.value.as < std::shared_ptr<resolvable> > () = yystack_[0].value.as < std::shared_ptr<resolvable> > (); } + break; + + case 62: // condition: "!" "x" + { yylhs.value.as < enum condition > () = condition::xz; } + break; + + case 63: // condition: "x" "--" + { yylhs.value.as < enum condition > () = condition::xnz__; } + break; + + case 64: // condition: "!" "y" + { yylhs.value.as < enum condition > () = condition::yz; } + break; + + case 65: // condition: "y" "--" + { yylhs.value.as < enum condition > () = condition::ynz__; } + break; + + case 66: // condition: "x" "!=" "y" + { yylhs.value.as < enum condition > () = condition::xney; } + break; + + case 67: // condition: "pin" + { yylhs.value.as < enum condition > () = condition::pin; } + break; + + case 68: // condition: "!" "osre" + { yylhs.value.as < enum condition > () = condition::osrez; } + break; + + case 69: // condition: %empty + { yylhs.value.as < enum condition > () = condition::al; } + break; + + case 70: // wait_source: "irq" comma value "rel" + { yylhs.value.as < std::shared_ptr<wait_source> > () = std::shared_ptr<wait_source>(new wait_source(wait_source::irq, yystack_[1].value.as < std::shared_ptr<resolvable> > (), true)); } + break; + + case 71: // wait_source: "irq" comma value + { yylhs.value.as < std::shared_ptr<wait_source> > () = std::shared_ptr<wait_source>(new wait_source(wait_source::irq, yystack_[0].value.as < std::shared_ptr<resolvable> > (), false)); } + break; + + case 72: // wait_source: "gpio" comma value + { yylhs.value.as < std::shared_ptr<wait_source> > () = std::shared_ptr<wait_source>(new wait_source(wait_source::gpio, yystack_[0].value.as < std::shared_ptr<resolvable> > ())); } + break; + + case 73: // wait_source: "pin" comma value + { yylhs.value.as < std::shared_ptr<wait_source> > () = std::shared_ptr<wait_source>(new wait_source(wait_source::pin, yystack_[0].value.as < std::shared_ptr<resolvable> > ())); } + break; + + case 76: // in_source: "pins" + { yylhs.value.as < enum in_out_set > () = in_out_set::in_out_set_pins; } + break; + + case 77: // in_source: "x" + { yylhs.value.as < enum in_out_set > () = in_out_set::in_out_set_x; } + break; + + case 78: // in_source: "y" + { yylhs.value.as < enum in_out_set > () = in_out_set::in_out_set_y; } + break; + + case 79: // in_source: "null" + { yylhs.value.as < enum in_out_set > () = in_out_set::in_out_null; } + break; + + case 80: // in_source: "isr" + { yylhs.value.as < enum in_out_set > () = in_out_set::in_out_isr; } + break; + + case 81: // in_source: "osr" + { yylhs.value.as < enum in_out_set > () = in_out_set::in_osr; } + break; + + case 82: // in_source: "status" + { yylhs.value.as < enum in_out_set > () = in_out_set::in_status; } + break; + + case 83: // out_target: "pins" + { yylhs.value.as < enum in_out_set > () = in_out_set::in_out_set_pins; } + break; + + case 84: // out_target: "x" + { yylhs.value.as < enum in_out_set > () = in_out_set::in_out_set_x; } + break; + + case 85: // out_target: "y" + { yylhs.value.as < enum in_out_set > () = in_out_set::in_out_set_y; } + break; + + case 86: // out_target: "null" + { yylhs.value.as < enum in_out_set > () = in_out_set::in_out_null; } + break; + + case 87: // out_target: "pindirs" + { yylhs.value.as < enum in_out_set > () = in_out_set::in_out_set_pindirs; } + break; + + case 88: // out_target: "isr" + { yylhs.value.as < enum in_out_set > () = in_out_set::in_out_isr; } + break; + + case 89: // out_target: "pc" + { yylhs.value.as < enum in_out_set > () = in_out_set::out_set_pc; } + break; + + case 90: // out_target: "exec" + { yylhs.value.as < enum in_out_set > () = in_out_set::out_exec; } + break; + + case 91: // mov_target: "pins" + { yylhs.value.as < enum mov > () = mov::pins; } + break; + + case 92: // mov_target: "x" + { yylhs.value.as < enum mov > () = mov::x; } + break; + + case 93: // mov_target: "y" + { yylhs.value.as < enum mov > () = mov::y; } + break; + + case 94: // mov_target: "exec" + { yylhs.value.as < enum mov > () = mov::exec; } + break; + + case 95: // mov_target: "pc" + { yylhs.value.as < enum mov > () = mov::pc; } + break; + + case 96: // mov_target: "isr" + { yylhs.value.as < enum mov > () = mov::isr; } + break; + + case 97: // mov_target: "osr" + { yylhs.value.as < enum mov > () = mov::osr; } + break; + + case 98: // mov_source: "pins" + { yylhs.value.as < enum mov > () = mov::pins; } + break; + + case 99: // mov_source: "x" + { yylhs.value.as < enum mov > () = mov::x; } + break; + + case 100: // mov_source: "y" + { yylhs.value.as < enum mov > () = mov::y; } + break; + + case 101: // mov_source: "null" + { yylhs.value.as < enum mov > () = mov::null; } + break; + + case 102: // mov_source: "status" + { yylhs.value.as < enum mov > () = mov::status; } + break; + + case 103: // mov_source: "isr" + { yylhs.value.as < enum mov > () = mov::isr; } + break; + + case 104: // mov_source: "osr" + { yylhs.value.as < enum mov > () = mov::osr; } + break; + + case 105: // mov_op: "!" + { yylhs.value.as < enum mov_op > () = mov_op::invert; } + break; + + case 106: // mov_op: "::" + { yylhs.value.as < enum mov_op > () = mov_op::bit_reverse; } + break; + + case 107: // mov_op: %empty + { yylhs.value.as < enum mov_op > () = mov_op::none; } + break; + + case 108: // set_target: "pins" + { yylhs.value.as < enum in_out_set > () = in_out_set::in_out_set_pins; } + break; + + case 109: // set_target: "x" + { yylhs.value.as < enum in_out_set > () = in_out_set::in_out_set_x; } + break; + + case 110: // set_target: "y" + { yylhs.value.as < enum in_out_set > () = in_out_set::in_out_set_y; } + break; + + case 111: // set_target: "pindirs" + { yylhs.value.as < enum in_out_set > () = in_out_set::in_out_set_pindirs; } + break; + + case 112: // if_full: "iffull" + { yylhs.value.as < bool > () = true; } + break; + + case 113: // if_full: %empty + { yylhs.value.as < bool > () = false; } + break; + + case 114: // if_empty: "ifempty" + { yylhs.value.as < bool > () = true; } + break; + + case 115: // if_empty: %empty + { yylhs.value.as < bool > () = false; } + break; + + case 116: // blocking: "block" + { yylhs.value.as < bool > () = true; } + break; + + case 117: // blocking: "noblock" + { yylhs.value.as < bool > () = false; } + break; + + case 118: // blocking: %empty + { yylhs.value.as < bool > () = true; } + break; + + case 119: // irq_modifiers: "clear" + { yylhs.value.as < enum irq > () = irq::clear; } + break; + + case 120: // irq_modifiers: "wait" + { yylhs.value.as < enum irq > () = irq::set_wait; } + break; + + case 121: // irq_modifiers: "nowait" + { yylhs.value.as < enum irq > () = irq::set; } + break; + + case 122: // irq_modifiers: "set" + { yylhs.value.as < enum irq > () = irq::set; } + break; + + case 123: // irq_modifiers: %empty + { yylhs.value.as < enum irq > () = irq::set; } + break; + + case 124: // symbol_def: "identifier" + { yylhs.value.as < std::shared_ptr<symbol> > () = std::shared_ptr<symbol>(new symbol(yylhs.location, yystack_[0].value.as < std::string > ())); } + break; + + case 125: // symbol_def: "public" "identifier" + { yylhs.value.as < std::shared_ptr<symbol> > () = std::shared_ptr<symbol>(new symbol(yylhs.location, yystack_[0].value.as < std::string > (), true)); } + break; + + case 126: // symbol_def: "*" "identifier" + { yylhs.value.as < std::shared_ptr<symbol> > () = std::shared_ptr<symbol>(new symbol(yylhs.location, yystack_[0].value.as < std::string > (), true)); } + break; + + + + default: + break; + } + } +#if YY_EXCEPTIONS + catch (const syntax_error& yyexc) + { + YYCDEBUG << "Caught exception: " << yyexc.what() << '\n'; + error (yyexc); + YYERROR; + } +#endif // YY_EXCEPTIONS + YY_SYMBOL_PRINT ("-> $$ =", yylhs); + yypop_ (yylen); + yylen = 0; + + // Shift the result of the reduction. + yypush_ (YY_NULLPTR, YY_MOVE (yylhs)); + } + goto yynewstate; + + + /*--------------------------------------. + | yyerrlab -- here on detecting error. | + `--------------------------------------*/ + yyerrlab: + // If not already recovering from an error, report this error. + if (!yyerrstatus_) + { + ++yynerrs_; + context yyctx (*this, yyla); + std::string msg = yysyntax_error_ (yyctx); + error (yyla.location, YY_MOVE (msg)); + } + + + yyerror_range[1].location = yyla.location; + if (yyerrstatus_ == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + // Return failure if at end of input. + if (yyla.kind () == symbol_kind::S_YYEOF) + YYABORT; + else if (!yyla.empty ()) + { + yy_destroy_ ("Error: discarding", yyla); + yyla.clear (); + } + } + + // Else will try to reuse lookahead token after shifting the error token. + goto yyerrlab1; + + + /*---------------------------------------------------. + | yyerrorlab -- error raised explicitly by YYERROR. | + `---------------------------------------------------*/ + yyerrorlab: + /* Pacify compilers when the user code never invokes YYERROR and + the label yyerrorlab therefore never appears in user code. */ + if (false) + YYERROR; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + yypop_ (yylen); + yylen = 0; + YY_STACK_PRINT (); + goto yyerrlab1; + + + /*-------------------------------------------------------------. + | yyerrlab1 -- common code for both syntax error and YYERROR. | + `-------------------------------------------------------------*/ + yyerrlab1: + yyerrstatus_ = 3; // Each real token shifted decrements this. + // Pop stack until we find a state that shifts the error token. + for (;;) + { + yyn = yypact_[+yystack_[0].state]; + if (!yy_pact_value_is_default_ (yyn)) + { + yyn += symbol_kind::S_YYerror; + if (0 <= yyn && yyn <= yylast_ + && yycheck_[yyn] == symbol_kind::S_YYerror) + { + yyn = yytable_[yyn]; + if (0 < yyn) + break; + } + } + + // Pop the current state because it cannot handle the error token. + if (yystack_.size () == 1) + YYABORT; + + yyerror_range[1].location = yystack_[0].location; + yy_destroy_ ("Error: popping", yystack_[0]); + yypop_ (); + YY_STACK_PRINT (); + } + { + stack_symbol_type error_token; + + yyerror_range[2].location = yyla.location; + YYLLOC_DEFAULT (error_token.location, yyerror_range, 2); + + // Shift the error token. + yy_lac_discard_ ("error recovery"); + error_token.state = state_type (yyn); + yypush_ ("Shifting", YY_MOVE (error_token)); + } + goto yynewstate; + + + /*-------------------------------------. + | yyacceptlab -- YYACCEPT comes here. | + `-------------------------------------*/ + yyacceptlab: + yyresult = 0; + goto yyreturn; + + + /*-----------------------------------. + | yyabortlab -- YYABORT comes here. | + `-----------------------------------*/ + yyabortlab: + yyresult = 1; + goto yyreturn; + + + /*-----------------------------------------------------. + | yyreturn -- parsing is finished, return the result. | + `-----------------------------------------------------*/ + yyreturn: + if (!yyla.empty ()) + yy_destroy_ ("Cleanup: discarding lookahead", yyla); + + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + yypop_ (yylen); + YY_STACK_PRINT (); + while (1 < yystack_.size ()) + { + yy_destroy_ ("Cleanup: popping", yystack_[0]); + yypop_ (); + } + + return yyresult; + } +#if YY_EXCEPTIONS + catch (...) + { + YYCDEBUG << "Exception caught: cleaning lookahead and stack\n"; + // Do not try to display the values of the reclaimed symbols, + // as their printers might throw an exception. + if (!yyla.empty ()) + yy_destroy_ (YY_NULLPTR, yyla); + + while (1 < yystack_.size ()) + { + yy_destroy_ (YY_NULLPTR, yystack_[0]); + yypop_ (); + } + throw; + } +#endif // YY_EXCEPTIONS + } + + void + parser::error (const syntax_error& yyexc) + { + error (yyexc.location, yyexc.what ()); + } + + /* Return YYSTR after stripping away unnecessary quotes and + backslashes, so that it's suitable for yyerror. The heuristic is + that double-quoting is unnecessary unless the string contains an + apostrophe, a comma, or backslash (other than backslash-backslash). + YYSTR is taken from yytname. */ + std::string + parser::yytnamerr_ (const char *yystr) + { + if (*yystr == '"') + { + std::string yyr; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + else + goto append; + + append: + default: + yyr += *yyp; + break; + + case '"': + return yyr; + } + do_not_strip_quotes: ; + } + + return yystr; + } + + std::string + parser::symbol_name (symbol_kind_type yysymbol) + { + return yytnamerr_ (yytname_[yysymbol]); + } + + + + // parser::context. + parser::context::context (const parser& yyparser, const symbol_type& yyla) + : yyparser_ (yyparser) + , yyla_ (yyla) + {} + + int + parser::context::expected_tokens (symbol_kind_type yyarg[], int yyargn) const + { + // Actual number of expected tokens + int yycount = 0; + +#if YYDEBUG + // Execute LAC once. We don't care if it is successful, we + // only do it for the sake of debugging output. + if (!yyparser_.yy_lac_established_) + yyparser_.yy_lac_check_ (yyla_.kind ()); +#endif + + for (int yyx = 0; yyx < YYNTOKENS; ++yyx) + { + symbol_kind_type yysym = YY_CAST (symbol_kind_type, yyx); + if (yysym != symbol_kind::S_YYerror + && yysym != symbol_kind::S_YYUNDEF + && yyparser_.yy_lac_check_ (yysym)) + { + if (!yyarg) + ++yycount; + else if (yycount == yyargn) + return 0; + else + yyarg[yycount++] = yysym; + } + } + if (yyarg && yycount == 0 && 0 < yyargn) + yyarg[0] = symbol_kind::S_YYEMPTY; + return yycount; + } + + + bool + parser::yy_lac_check_ (symbol_kind_type yytoken) const + { + // Logically, the yylac_stack's lifetime is confined to this function. + // Clear it, to get rid of potential left-overs from previous call. + yylac_stack_.clear (); + // Reduce until we encounter a shift and thereby accept the token. +#if YYDEBUG + YYCDEBUG << "LAC: checking lookahead " << symbol_name (yytoken) << ':'; +#endif + std::ptrdiff_t lac_top = 0; + while (true) + { + state_type top_state = (yylac_stack_.empty () + ? yystack_[lac_top].state + : yylac_stack_.back ()); + int yyrule = yypact_[+top_state]; + if (yy_pact_value_is_default_ (yyrule) + || (yyrule += yytoken) < 0 || yylast_ < yyrule + || yycheck_[yyrule] != yytoken) + { + // Use the default action. + yyrule = yydefact_[+top_state]; + if (yyrule == 0) + { + YYCDEBUG << " Err\n"; + return false; + } + } + else + { + // Use the action from yytable. + yyrule = yytable_[yyrule]; + if (yy_table_value_is_error_ (yyrule)) + { + YYCDEBUG << " Err\n"; + return false; + } + if (0 < yyrule) + { + YYCDEBUG << " S" << yyrule << '\n'; + return true; + } + yyrule = -yyrule; + } + // By now we know we have to simulate a reduce. + YYCDEBUG << " R" << yyrule - 1; + // Pop the corresponding number of values from the stack. + { + std::ptrdiff_t yylen = yyr2_[yyrule]; + // First pop from the LAC stack as many tokens as possible. + std::ptrdiff_t lac_size = std::ptrdiff_t (yylac_stack_.size ()); + if (yylen < lac_size) + { + yylac_stack_.resize (std::size_t (lac_size - yylen)); + yylen = 0; + } + else if (lac_size) + { + yylac_stack_.clear (); + yylen -= lac_size; + } + // Only afterwards look at the main stack. + // We simulate popping elements by incrementing lac_top. + lac_top += yylen; + } + // Keep top_state in sync with the updated stack. + top_state = (yylac_stack_.empty () + ? yystack_[lac_top].state + : yylac_stack_.back ()); + // Push the resulting state of the reduction. + state_type state = yy_lr_goto_state_ (top_state, yyr1_[yyrule]); + YYCDEBUG << " G" << int (state); + yylac_stack_.push_back (state); + } + } + + // Establish the initial context if no initial context currently exists. + bool + parser::yy_lac_establish_ (symbol_kind_type yytoken) + { + /* Establish the initial context for the current lookahead if no initial + context is currently established. + + We define a context as a snapshot of the parser stacks. We define + the initial context for a lookahead as the context in which the + parser initially examines that lookahead in order to select a + syntactic action. Thus, if the lookahead eventually proves + syntactically unacceptable (possibly in a later context reached via a + series of reductions), the initial context can be used to determine + the exact set of tokens that would be syntactically acceptable in the + lookahead's place. Moreover, it is the context after which any + further semantic actions would be erroneous because they would be + determined by a syntactically unacceptable token. + + yy_lac_establish_ should be invoked when a reduction is about to be + performed in an inconsistent state (which, for the purposes of LAC, + includes consistent states that don't know they're consistent because + their default reductions have been disabled). + + For parse.lac=full, the implementation of yy_lac_establish_ is as + follows. If no initial context is currently established for the + current lookahead, then check if that lookahead can eventually be + shifted if syntactic actions continue from the current context. */ + if (!yy_lac_established_) + { +#if YYDEBUG + YYCDEBUG << "LAC: initial context established for " + << symbol_name (yytoken) << '\n'; +#endif + yy_lac_established_ = true; + return yy_lac_check_ (yytoken); + } + return true; + } + + // Discard any previous initial lookahead context. + void + parser::yy_lac_discard_ (const char* evt) + { + /* Discard any previous initial lookahead context because of Event, + which may be a lookahead change or an invalidation of the currently + established initial context for the current lookahead. + + The most common example of a lookahead change is a shift. An example + of both cases is syntax error recovery. That is, a syntax error + occurs when the lookahead is syntactically erroneous for the + currently established initial context, so error recovery manipulates + the parser stacks to try to find a new initial context in which the + current lookahead is syntactically acceptable. If it fails to find + such a context, it discards the lookahead. */ + if (yy_lac_established_) + { + YYCDEBUG << "LAC: initial context discarded due to " + << evt << '\n'; + yy_lac_established_ = false; + } + } + + int + parser::yy_syntax_error_arguments_ (const context& yyctx, + symbol_kind_type yyarg[], int yyargn) const + { + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yyla) is + if this state is a consistent state with a default action. + Thus, detecting the absence of a lookahead is sufficient to + determine that there is no unexpected or expected token to + report. In that case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is + a consistent state with a default action. There might have + been a previous inconsistent state, consistent state with a + non-default action, or user semantic action that manipulated + yyla. (However, yyla is currently not documented for users.) + In the first two cases, it might appear that the current syntax + error should have been detected in the previous state when + yy_lac_check was invoked. However, at that time, there might + have been a different syntax error that discarded a different + initial context during error recovery, leaving behind the + current lookahead. + */ + + if (!yyctx.lookahead ().empty ()) + { + if (yyarg) + yyarg[0] = yyctx.token (); + int yyn = yyctx.expected_tokens (yyarg ? yyarg + 1 : yyarg, yyargn - 1); + return yyn + 1; + } + return 0; + } + + // Generate an error message. + std::string + parser::yysyntax_error_ (const context& yyctx) const + { + // Its maximum. + enum { YYARGS_MAX = 5 }; + // Arguments of yyformat. + symbol_kind_type yyarg[YYARGS_MAX]; + int yycount = yy_syntax_error_arguments_ (yyctx, yyarg, YYARGS_MAX); + + char const* yyformat = YY_NULLPTR; + switch (yycount) + { +#define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + default: // Avoid compiler warnings. + YYCASE_ (0, YY_("syntax error")); + YYCASE_ (1, YY_("syntax error, unexpected %s")); + YYCASE_ (2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_ (3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_ (4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_ (5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +#undef YYCASE_ + } + + std::string yyres; + // Argument number. + std::ptrdiff_t yyi = 0; + for (char const* yyp = yyformat; *yyp; ++yyp) + if (yyp[0] == '%' && yyp[1] == 's' && yyi < yycount) + { + yyres += symbol_name (yyarg[yyi++]); + ++yyp; + } + else + yyres += *yyp; + return yyres; + } + + + const signed char parser::yypact_ninf_ = -52; + + const signed char parser::yytable_ninf_ = -12; + + const short + parser::yypact_[] = + { + 3, -52, -41, -39, -52, -52, -3, 5, 5, 5, + 7, 44, 10, 0, 101, 18, 30, 94, 51, 50, + -52, 20, -52, 13, -52, 88, 17, -52, -52, 129, + -52, -52, 2, 85, -52, -52, 1, 1, -52, -52, + 40, -52, -52, -52, 42, 58, -52, 28, 96, 120, + 120, 120, 120, 15, -52, -52, -52, -52, -52, -52, + -52, -52, 120, -52, -52, -52, -52, -52, -52, -52, + -52, 120, -52, 63, -52, 63, -52, -52, -52, -52, + -52, -52, -52, 120, -52, -52, -52, -52, 5, -52, + -52, -52, -52, 120, -52, -52, -52, -52, 3, -52, + 1, 5, 45, 130, -52, 1, 1, -52, 177, 162, + -52, 97, 132, -52, -52, -52, -52, 87, -52, -52, + 1, 5, 5, 5, 5, -52, 5, 5, -52, -52, + -52, -52, 29, 118, 5, -52, 170, -52, -52, -52, + 182, 177, 1, 1, 1, 1, 1, 1, 1, -52, + -52, -51, -52, 177, 119, -52, -52, -52, -52, -52, + -52, -52, 82, -52, -52, -52, 182, 182, 107, 107, + -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52 + }; + + const signed char + parser::yydefact_[] = + { + 0, 12, 0, 0, 21, 22, 0, 0, 0, 0, + 0, 69, 0, 0, 0, 113, 115, 0, 123, 0, + 47, 0, 124, 0, 28, 0, 0, 3, 10, 9, + 6, 7, 46, 0, 126, 5, 0, 0, 30, 29, + 20, 23, 16, 27, 0, 0, 67, 0, 0, 75, + 75, 75, 75, 0, 51, 76, 79, 77, 78, 80, + 81, 82, 75, 83, 86, 87, 84, 85, 90, 89, + 88, 75, 112, 118, 114, 118, 91, 92, 93, 94, + 95, 96, 97, 75, 120, 122, 121, 119, 0, 108, + 111, 109, 110, 75, 125, 13, 1, 2, 0, 8, + 0, 0, 45, 44, 14, 0, 0, 32, 15, 0, + 19, 18, 0, 68, 62, 64, 63, 0, 65, 74, + 0, 0, 0, 0, 0, 49, 0, 0, 116, 117, + 54, 55, 107, 58, 0, 4, 0, 61, 43, 42, + 40, 41, 0, 0, 0, 0, 0, 0, 0, 31, + 17, 0, 66, 48, 71, 73, 72, 50, 52, 53, + 105, 106, 0, 57, 59, 60, 33, 34, 35, 36, + 37, 38, 39, 25, 26, 24, 70, 98, 101, 99, + 100, 103, 104, 102, 56 + }; + + const short + parser::yypgoto_[] = + { + -52, -52, -52, 102, -52, -52, -52, -7, -14, 172, + -52, 99, 103, -52, 146, 25, -52, -52, -52, -52, + -52, -52, -52, -52, 128, -52, 198 + }; + + const short + parser::yydefgoto_[] = + { + -1, 25, 26, 27, 28, 29, 30, 107, 108, 31, + 32, 102, 103, 49, 54, 120, 62, 71, 83, 184, + 162, 93, 73, 75, 130, 88, 33 + }; + + const short + parser::yytable_[] = + { + 40, 41, 42, -11, 1, 53, -11, 37, 43, 2, + 100, 37, 105, 173, 174, 2, 37, 97, 175, 124, + 98, 106, 34, 109, 35, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 55, 56, 116, 117, 50, 160, 161, + 51, 52, 50, 57, 58, 51, 52, 59, 60, 21, + 22, 61, 101, 45, 38, 21, 22, 72, 38, 23, + 39, 24, 44, 38, 39, 121, 122, 123, 74, 39, + 95, 133, 84, 94, 46, 110, 136, 126, 96, 85, + 104, 140, 141, 89, 137, 90, 127, 47, 48, 111, + 113, 86, 87, 91, 92, 101, 153, 112, 132, 128, + 129, 114, 115, 118, 154, 155, 156, 157, 134, 158, + 159, 146, 147, 148, 119, 177, 178, 164, 166, 167, + 168, 169, 170, 171, 172, 179, 180, 76, 100, 181, + 182, 152, 150, 183, 63, 64, 65, 77, 78, 79, + 80, 81, 82, 151, 66, 67, 68, 69, 70, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 149, + 163, 176, 142, 143, 144, 145, 146, 147, 148, 165, + 142, 143, 144, 145, 146, 147, 148, 142, 143, 144, + 145, 146, 147, 148, 144, 145, 146, 147, 148, 125, + 135, 99, 139, 131, 36, 138 + }; + + const unsigned char + parser::yycheck_[] = + { + 7, 8, 9, 0, 1, 12, 3, 6, 1, 12, + 8, 6, 11, 64, 65, 12, 6, 0, 69, 4, + 3, 20, 63, 37, 63, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 43, 44, 17, 18, 37, 19, 20, + 40, 41, 37, 53, 54, 40, 41, 57, 58, 62, + 63, 61, 60, 19, 63, 62, 63, 49, 63, 66, + 69, 68, 65, 63, 69, 50, 51, 52, 48, 69, + 67, 88, 31, 63, 40, 45, 100, 62, 0, 38, + 5, 105, 106, 43, 101, 45, 71, 53, 54, 59, + 42, 50, 51, 53, 54, 60, 120, 65, 83, 46, + 47, 53, 54, 17, 121, 122, 123, 124, 93, 126, + 127, 14, 15, 16, 4, 43, 44, 134, 142, 143, + 144, 145, 146, 147, 148, 53, 54, 43, 8, 57, + 58, 54, 45, 61, 43, 44, 45, 53, 54, 55, + 56, 57, 58, 21, 53, 54, 55, 56, 57, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 7, + 52, 52, 10, 11, 12, 13, 14, 15, 16, 9, + 10, 11, 12, 13, 14, 15, 16, 10, 11, 12, + 13, 14, 15, 16, 12, 13, 14, 15, 16, 53, + 98, 29, 103, 75, 6, 102 + }; + + const signed char + parser::yystos_[] = + { + 0, 1, 12, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 62, 63, 66, 68, 71, 72, 73, 74, 75, + 76, 79, 80, 96, 63, 63, 96, 6, 63, 69, + 77, 77, 77, 1, 65, 19, 40, 53, 54, 83, + 37, 40, 41, 77, 84, 43, 44, 53, 54, 57, + 58, 61, 86, 43, 44, 45, 53, 54, 55, 56, + 57, 87, 49, 92, 48, 93, 43, 53, 54, 55, + 56, 57, 58, 88, 31, 38, 50, 51, 95, 43, + 45, 53, 54, 91, 63, 67, 0, 0, 3, 79, + 8, 60, 81, 82, 5, 11, 20, 77, 78, 78, + 45, 59, 65, 42, 53, 54, 17, 18, 17, 4, + 85, 85, 85, 85, 4, 84, 85, 85, 46, 47, + 94, 94, 85, 77, 85, 73, 78, 77, 82, 81, + 78, 78, 10, 11, 12, 13, 14, 15, 16, 7, + 45, 21, 54, 78, 77, 77, 77, 77, 77, 77, + 19, 20, 90, 52, 77, 9, 78, 78, 78, 78, + 78, 78, 78, 64, 65, 69, 52, 43, 44, 53, + 54, 57, 58, 61, 89 + }; + + const signed char + parser::yyr1_[] = + { + 0, 70, 71, 72, 72, 73, 73, 73, 73, 73, + 73, 73, 73, 74, 75, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 77, + 77, 77, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 79, 79, 79, 79, 79, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 81, 82, 83, 83, 83, 83, 83, 83, 83, 83, + 84, 84, 84, 84, 85, 85, 86, 86, 86, 86, + 86, 86, 86, 87, 87, 87, 87, 87, 87, 87, + 87, 88, 88, 88, 88, 88, 88, 88, 89, 89, + 89, 89, 89, 89, 89, 90, 90, 90, 91, 91, + 91, 91, 92, 92, 93, 93, 94, 94, 94, 95, + 95, 95, 95, 95, 96, 96, 96 + }; + + const signed char + parser::yyr2_[] = + { + 0, 2, 2, 1, 3, 2, 1, 1, 2, 1, + 1, 0, 1, 2, 2, 3, 2, 4, 3, 3, + 2, 1, 1, 2, 5, 5, 5, 2, 1, 1, + 1, 3, 1, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 3, 3, 2, 2, 1, 1, 4, 3, + 4, 2, 4, 4, 3, 3, 5, 4, 3, 4, + 3, 2, 2, 2, 2, 2, 3, 1, 2, 0, + 4, 3, 3, 3, 1, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, + 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, + 1, 1, 1, 0, 1, 2, 2 + }; + + +#if YYDEBUG || 1 + // YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + // First, the terminals, then, starting at \a YYNTOKENS, nonterminals. + const char* + const parser::yytname_[] = + { + "\"end of file\"", "error", "\"invalid token\"", "\"end of line\"", + "\",\"", "\":\"", "\"(\"", "\")\"", "\"[\"", "\"]\"", "\"+\"", "\"-\"", + "\"*\"", "\"/\"", "\"|\"", "\"&\"", "\"^\"", "\"--\"", "\"!=\"", "\"!\"", + "\"::\"", "\"=\"", "\".program\"", "\".wrap_target\"", "\".wrap\"", + "\".define\"", "\".side_set\"", "\".word\"", "\".origin\"", + "\".lang_opt\"", "\"jmp\"", "\"wait\"", "\"in\"", "\"out\"", "\"push\"", + "\"pull\"", "\"mov\"", "\"irq\"", "\"set\"", "\"nop\"", "\"pin\"", + "\"gpio\"", "\"osre\"", "\"pins\"", "\"null\"", "\"pindirs\"", + "\"block\"", "\"noblock\"", "\"ifempty\"", "\"iffull\"", "\"nowait\"", + "\"clear\"", "\"rel\"", "\"x\"", "\"y\"", "\"exec\"", "\"pc\"", + "\"isr\"", "\"osr\"", "\"opt\"", "\"side\"", "\"status\"", "\"public\"", + "\"identifier\"", "\"string\"", "\"text\"", "\"code block\"", "\"%}\"", + "UNKNOWN_DIRECTIVE", "\"integer\"", "$accept", "file", "lines", "line", + "code_block", "label_decl", "directive", "value", "expression", + "instruction", "base_instruction", "delay", "sideset", "condition", + "wait_source", "comma", "in_source", "out_target", "mov_target", + "mov_source", "mov_op", "set_target", "if_full", "if_empty", "blocking", + "irq_modifiers", "symbol_def", YY_NULLPTR + }; +#endif + + +#if YYDEBUG + const short + parser::yyrline_[] = + { + 0, 136, 136, 140, 141, 144, 145, 146, 147, 148, + 149, 150, 151, 155, 159, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 173, 174, 175, 180, + 181, 182, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 199, 200, 201, 202, 203, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 224, 228, 232, 233, 234, 235, 236, 237, 238, 239, + 243, 244, 245, 246, 248, 248, 251, 252, 253, 254, + 255, 256, 257, 260, 261, 262, 263, 264, 265, 266, + 267, 270, 271, 272, 273, 274, 275, 276, 279, 280, + 281, 282, 283, 284, 285, 289, 290, 291, 295, 296, + 297, 298, 302, 303, 307, 308, 312, 313, 314, 318, + 319, 320, 321, 322, 326, 327, 328 + }; + + void + parser::yy_stack_print_ () const + { + *yycdebug_ << "Stack now"; + for (stack_type::const_iterator + i = yystack_.begin (), + i_end = yystack_.end (); + i != i_end; ++i) + *yycdebug_ << ' ' << int (i->state); + *yycdebug_ << '\n'; + } + + void + parser::yy_reduce_print_ (int yyrule) const + { + int yylno = yyrline_[yyrule]; + int yynrhs = yyr2_[yyrule]; + // Print the symbols being reduced, and their result. + *yycdebug_ << "Reducing stack by rule " << yyrule - 1 + << " (line " << yylno << "):\n"; + // The symbols being reduced. + for (int yyi = 0; yyi < yynrhs; yyi++) + YY_SYMBOL_PRINT (" $" << yyi + 1 << " =", + yystack_[(yynrhs) - (yyi + 1)]); + } +#endif // YYDEBUG + + +} // yy + + +void yy::parser::error(const location_type& l, const std::string& m) +{ + if (l.begin.filename) { + std::cerr << l << ": " << m << '\n'; + pioasm.error_count++; + if (l.begin.line == l.end.line && *l.begin.filename == *l.end.filename) { + std::ifstream file(l.begin.filename->c_str()); + std::string line; + for(int i = 0; i < l.begin.line; ++i) { + std::getline(file, line); + } + fprintf(stderr, "%5d | %s\n", l.begin.line, line.c_str()); + fprintf(stderr, "%5s | %*s", "", l.begin.column, "^"); + for (int i = l.begin.column; i < l.end.column - 1; i++) { + putc ('~', stderr); + } + putc ('\n', stderr); + } + } else { + std::cerr << m << '\n'; + } +} + diff --git a/circuitpython/ports/raspberrypi/sdk/tools/pioasm/gen/parser.hpp b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/gen/parser.hpp new file mode 100644 index 0000000..11d8393 --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/gen/parser.hpp @@ -0,0 +1,2894 @@ +// A Bison parser, made by GNU Bison 3.7.2. + +// Skeleton interface for Bison LALR(1) parsers in C++ + +// Copyright (C) 2002-2015, 2018-2020 Free Software Foundation, Inc. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +// As a special exception, you may create a larger work that contains +// part or all of the Bison parser skeleton and distribute that work +// under terms of your choice, so long as that work isn't itself a +// parser generator using the skeleton or a modified version thereof +// as a parser skeleton. Alternatively, if you modify or redistribute +// the parser skeleton itself, you may (at your option) remove this +// special exception, which will cause the skeleton and the resulting +// Bison output files to be licensed under the GNU General Public +// License without this special exception. + +// This special exception was added by the Free Software Foundation in +// version 2.2 of Bison. + + +/** + ** \file pico_sdk/tools/pioasm/gen/parser.hpp + ** Define the yy::parser class. + */ + +// C++ LALR(1) parser skeleton written by Akim Demaille. + +// DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, +// especially those whose name start with YY_ or yy_. They are +// private implementation details that can be changed or removed. + +#ifndef YY_YY_HOME_GRAHAM_DEV_MU_PICO_SDK_TOOLS_PIOASM_GEN_PARSER_HPP_INCLUDED +# define YY_YY_HOME_GRAHAM_DEV_MU_PICO_SDK_TOOLS_PIOASM_GEN_PARSER_HPP_INCLUDED +// "%code requires" blocks. + + #include <string> + #include <fstream> + #include <sstream> + #include "pio_types.h" + struct pio_assembler; + + #ifdef _MSC_VER + #pragma warning(disable : 4065) // default only switch statement + #endif + + + +# include <cstdlib> // std::abort +# include <iostream> +# include <stdexcept> +# include <string> +# include <vector> + +#if defined __cplusplus +# define YY_CPLUSPLUS __cplusplus +#else +# define YY_CPLUSPLUS 199711L +#endif + +// Support move semantics when possible. +#if 201103L <= YY_CPLUSPLUS +# define YY_MOVE std::move +# define YY_MOVE_OR_COPY move +# define YY_MOVE_REF(Type) Type&& +# define YY_RVREF(Type) Type&& +# define YY_COPY(Type) Type +#else +# define YY_MOVE +# define YY_MOVE_OR_COPY copy +# define YY_MOVE_REF(Type) Type& +# define YY_RVREF(Type) const Type& +# define YY_COPY(Type) const Type& +#endif + +// Support noexcept when possible. +#if 201103L <= YY_CPLUSPLUS +# define YY_NOEXCEPT noexcept +# define YY_NOTHROW +#else +# define YY_NOEXCEPT +# define YY_NOTHROW throw () +#endif + +// Support constexpr when possible. +#if 201703 <= YY_CPLUSPLUS +# define YY_CONSTEXPR constexpr +#else +# define YY_CONSTEXPR +#endif +# include "location.h" + +#ifndef YY_ASSERT +# include <cassert> +# define YY_ASSERT assert +#endif + + +#ifndef YY_ATTRIBUTE_PURE +# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) +# else +# define YY_ATTRIBUTE_PURE +# endif +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +# else +# define YY_ATTRIBUTE_UNUSED +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + +#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ +# define YY_IGNORE_USELESS_CAST_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") +# define YY_IGNORE_USELESS_CAST_END \ + _Pragma ("GCC diagnostic pop") +#endif +#ifndef YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_END +#endif + +# ifndef YY_CAST +# ifdef __cplusplus +# define YY_CAST(Type, Val) static_cast<Type> (Val) +# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val) +# else +# define YY_CAST(Type, Val) ((Type) (Val)) +# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) +# endif +# endif +# ifndef YY_NULLPTR +# if defined __cplusplus +# if 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# else +# define YY_NULLPTR ((void*)0) +# endif +# endif + +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +namespace yy { + + + + + /// A Bison parser. + class parser + { + public: +#ifndef YYSTYPE + /// A buffer to store and retrieve objects. + /// + /// Sort of a variant, but does not keep track of the nature + /// of the stored data, since that knowledge is available + /// via the current parser state. + class semantic_type + { + public: + /// Type of *this. + typedef semantic_type self_type; + + /// Empty construction. + semantic_type () YY_NOEXCEPT + : yybuffer_ () + {} + + /// Construct and fill. + template <typename T> + semantic_type (YY_RVREF (T) t) + { + YY_ASSERT (sizeof (T) <= size); + new (yyas_<T> ()) T (YY_MOVE (t)); + } + +#if 201103L <= YY_CPLUSPLUS + /// Non copyable. + semantic_type (const self_type&) = delete; + /// Non copyable. + self_type& operator= (const self_type&) = delete; +#endif + + /// Destruction, allowed only if empty. + ~semantic_type () YY_NOEXCEPT + {} + +# if 201103L <= YY_CPLUSPLUS + /// Instantiate a \a T in here from \a t. + template <typename T, typename... U> + T& + emplace (U&&... u) + { + return *new (yyas_<T> ()) T (std::forward <U>(u)...); + } +# else + /// Instantiate an empty \a T in here. + template <typename T> + T& + emplace () + { + return *new (yyas_<T> ()) T (); + } + + /// Instantiate a \a T in here from \a t. + template <typename T> + T& + emplace (const T& t) + { + return *new (yyas_<T> ()) T (t); + } +# endif + + /// Instantiate an empty \a T in here. + /// Obsolete, use emplace. + template <typename T> + T& + build () + { + return emplace<T> (); + } + + /// Instantiate a \a T in here from \a t. + /// Obsolete, use emplace. + template <typename T> + T& + build (const T& t) + { + return emplace<T> (t); + } + + /// Accessor to a built \a T. + template <typename T> + T& + as () YY_NOEXCEPT + { + return *yyas_<T> (); + } + + /// Const accessor to a built \a T (for %printer). + template <typename T> + const T& + as () const YY_NOEXCEPT + { + return *yyas_<T> (); + } + + /// Swap the content with \a that, of same type. + /// + /// Both variants must be built beforehand, because swapping the actual + /// data requires reading it (with as()), and this is not possible on + /// unconstructed variants: it would require some dynamic testing, which + /// should not be the variant's responsibility. + /// Swapping between built and (possibly) non-built is done with + /// self_type::move (). + template <typename T> + void + swap (self_type& that) YY_NOEXCEPT + { + std::swap (as<T> (), that.as<T> ()); + } + + /// Move the content of \a that to this. + /// + /// Destroys \a that. + template <typename T> + void + move (self_type& that) + { +# if 201103L <= YY_CPLUSPLUS + emplace<T> (std::move (that.as<T> ())); +# else + emplace<T> (); + swap<T> (that); +# endif + that.destroy<T> (); + } + +# if 201103L <= YY_CPLUSPLUS + /// Move the content of \a that to this. + template <typename T> + void + move (self_type&& that) + { + emplace<T> (std::move (that.as<T> ())); + that.destroy<T> (); + } +#endif + + /// Copy the content of \a that to this. + template <typename T> + void + copy (const self_type& that) + { + emplace<T> (that.as<T> ()); + } + + /// Destroy the stored \a T. + template <typename T> + void + destroy () + { + as<T> ().~T (); + } + + private: +#if YY_CPLUSPLUS < 201103L + /// Non copyable. + semantic_type (const self_type&); + /// Non copyable. + self_type& operator= (const self_type&); +#endif + + /// Accessor to raw memory as \a T. + template <typename T> + T* + yyas_ () YY_NOEXCEPT + { + void *yyp = yybuffer_.yyraw; + return static_cast<T*> (yyp); + } + + /// Const accessor to raw memory as \a T. + template <typename T> + const T* + yyas_ () const YY_NOEXCEPT + { + const void *yyp = yybuffer_.yyraw; + return static_cast<const T*> (yyp); + } + + /// An auxiliary type to compute the largest semantic type. + union union_type + { + // if_full + // if_empty + // blocking + char dummy1[sizeof (bool)]; + + // condition + char dummy2[sizeof (enum condition)]; + + // in_source + // out_target + // set_target + char dummy3[sizeof (enum in_out_set)]; + + // irq_modifiers + char dummy4[sizeof (enum irq)]; + + // mov_target + // mov_source + char dummy5[sizeof (enum mov)]; + + // mov_op + char dummy6[sizeof (enum mov_op)]; + + // "integer" + char dummy7[sizeof (int)]; + + // instruction + // base_instruction + char dummy8[sizeof (std::shared_ptr<instruction>)]; + + // value + // expression + // delay + // sideset + char dummy9[sizeof (std::shared_ptr<resolvable>)]; + + // label_decl + // symbol_def + char dummy10[sizeof (std::shared_ptr<symbol>)]; + + // wait_source + char dummy11[sizeof (std::shared_ptr<wait_source>)]; + + // "identifier" + // "string" + // "text" + // "code block" + // "%}" + // UNKNOWN_DIRECTIVE + char dummy12[sizeof (std::string)]; + }; + + /// The size of the largest semantic type. + enum { size = sizeof (union_type) }; + + /// A buffer to store semantic values. + union + { + /// Strongest alignment constraints. + long double yyalign_me; + /// A buffer large enough to store any of the semantic values. + char yyraw[size]; + } yybuffer_; + }; + +#else + typedef YYSTYPE semantic_type; +#endif + /// Symbol locations. + typedef location location_type; + + /// Syntax errors thrown from user actions. + struct syntax_error : std::runtime_error + { + syntax_error (const location_type& l, const std::string& m) + : std::runtime_error (m) + , location (l) + {} + + syntax_error (const syntax_error& s) + : std::runtime_error (s.what ()) + , location (s.location) + {} + + ~syntax_error () YY_NOEXCEPT YY_NOTHROW; + + location_type location; + }; + + /// Token kinds. + struct token + { + enum token_kind_type + { + TOK_YYEMPTY = -2, + TOK_END = 0, // "end of file" + TOK_YYerror = 256, // error + TOK_YYUNDEF = 257, // "invalid token" + TOK_NEWLINE = 258, // "end of line" + TOK_COMMA = 259, // "," + TOK_COLON = 260, // ":" + TOK_LPAREN = 261, // "(" + TOK_RPAREN = 262, // ")" + TOK_LBRACKET = 263, // "[" + TOK_RBRACKET = 264, // "]" + TOK_PLUS = 265, // "+" + TOK_MINUS = 266, // "-" + TOK_MULTIPLY = 267, // "*" + TOK_DIVIDE = 268, // "/" + TOK_OR = 269, // "|" + TOK_AND = 270, // "&" + TOK_XOR = 271, // "^" + TOK_POST_DECREMENT = 272, // "--" + TOK_NOT_EQUAL = 273, // "!=" + TOK_NOT = 274, // "!" + TOK_REVERSE = 275, // "::" + TOK_EQUAL = 276, // "=" + TOK_PROGRAM = 277, // ".program" + TOK_WRAP_TARGET = 278, // ".wrap_target" + TOK_WRAP = 279, // ".wrap" + TOK_DEFINE = 280, // ".define" + TOK_SIDE_SET = 281, // ".side_set" + TOK_WORD = 282, // ".word" + TOK_ORIGIN = 283, // ".origin" + TOK_LANG_OPT = 284, // ".lang_opt" + TOK_JMP = 285, // "jmp" + TOK_WAIT = 286, // "wait" + TOK_IN = 287, // "in" + TOK_OUT = 288, // "out" + TOK_PUSH = 289, // "push" + TOK_PULL = 290, // "pull" + TOK_MOV = 291, // "mov" + TOK_IRQ = 292, // "irq" + TOK_SET = 293, // "set" + TOK_NOP = 294, // "nop" + TOK_PIN = 295, // "pin" + TOK_GPIO = 296, // "gpio" + TOK_OSRE = 297, // "osre" + TOK_PINS = 298, // "pins" + TOK_NULL = 299, // "null" + TOK_PINDIRS = 300, // "pindirs" + TOK_BLOCK = 301, // "block" + TOK_NOBLOCK = 302, // "noblock" + TOK_IFEMPTY = 303, // "ifempty" + TOK_IFFULL = 304, // "iffull" + TOK_NOWAIT = 305, // "nowait" + TOK_CLEAR = 306, // "clear" + TOK_REL = 307, // "rel" + TOK_X = 308, // "x" + TOK_Y = 309, // "y" + TOK_EXEC = 310, // "exec" + TOK_PC = 311, // "pc" + TOK_ISR = 312, // "isr" + TOK_OSR = 313, // "osr" + TOK_OPTIONAL = 314, // "opt" + TOK_SIDE = 315, // "side" + TOK_STATUS = 316, // "status" + TOK_PUBLIC = 317, // "public" + TOK_ID = 318, // "identifier" + TOK_STRING = 319, // "string" + TOK_NON_WS = 320, // "text" + TOK_CODE_BLOCK_START = 321, // "code block" + TOK_CODE_BLOCK_CONTENTS = 322, // "%}" + TOK_UNKNOWN_DIRECTIVE = 323, // UNKNOWN_DIRECTIVE + TOK_INT = 324 // "integer" + }; + /// Backward compatibility alias (Bison 3.6). + typedef token_kind_type yytokentype; + }; + + /// Token kind, as returned by yylex. + typedef token::yytokentype token_kind_type; + + /// Backward compatibility alias (Bison 3.6). + typedef token_kind_type token_type; + + /// Symbol kinds. + struct symbol_kind + { + enum symbol_kind_type + { + YYNTOKENS = 70, ///< Number of tokens. + S_YYEMPTY = -2, + S_YYEOF = 0, // "end of file" + S_YYerror = 1, // error + S_YYUNDEF = 2, // "invalid token" + S_NEWLINE = 3, // "end of line" + S_COMMA = 4, // "," + S_COLON = 5, // ":" + S_LPAREN = 6, // "(" + S_RPAREN = 7, // ")" + S_LBRACKET = 8, // "[" + S_RBRACKET = 9, // "]" + S_PLUS = 10, // "+" + S_MINUS = 11, // "-" + S_MULTIPLY = 12, // "*" + S_DIVIDE = 13, // "/" + S_OR = 14, // "|" + S_AND = 15, // "&" + S_XOR = 16, // "^" + S_POST_DECREMENT = 17, // "--" + S_NOT_EQUAL = 18, // "!=" + S_NOT = 19, // "!" + S_REVERSE = 20, // "::" + S_EQUAL = 21, // "=" + S_PROGRAM = 22, // ".program" + S_WRAP_TARGET = 23, // ".wrap_target" + S_WRAP = 24, // ".wrap" + S_DEFINE = 25, // ".define" + S_SIDE_SET = 26, // ".side_set" + S_WORD = 27, // ".word" + S_ORIGIN = 28, // ".origin" + S_LANG_OPT = 29, // ".lang_opt" + S_JMP = 30, // "jmp" + S_WAIT = 31, // "wait" + S_IN = 32, // "in" + S_OUT = 33, // "out" + S_PUSH = 34, // "push" + S_PULL = 35, // "pull" + S_MOV = 36, // "mov" + S_IRQ = 37, // "irq" + S_SET = 38, // "set" + S_NOP = 39, // "nop" + S_PIN = 40, // "pin" + S_GPIO = 41, // "gpio" + S_OSRE = 42, // "osre" + S_PINS = 43, // "pins" + S_NULL = 44, // "null" + S_PINDIRS = 45, // "pindirs" + S_BLOCK = 46, // "block" + S_NOBLOCK = 47, // "noblock" + S_IFEMPTY = 48, // "ifempty" + S_IFFULL = 49, // "iffull" + S_NOWAIT = 50, // "nowait" + S_CLEAR = 51, // "clear" + S_REL = 52, // "rel" + S_X = 53, // "x" + S_Y = 54, // "y" + S_EXEC = 55, // "exec" + S_PC = 56, // "pc" + S_ISR = 57, // "isr" + S_OSR = 58, // "osr" + S_OPTIONAL = 59, // "opt" + S_SIDE = 60, // "side" + S_STATUS = 61, // "status" + S_PUBLIC = 62, // "public" + S_ID = 63, // "identifier" + S_STRING = 64, // "string" + S_NON_WS = 65, // "text" + S_CODE_BLOCK_START = 66, // "code block" + S_CODE_BLOCK_CONTENTS = 67, // "%}" + S_UNKNOWN_DIRECTIVE = 68, // UNKNOWN_DIRECTIVE + S_INT = 69, // "integer" + S_YYACCEPT = 70, // $accept + S_file = 71, // file + S_lines = 72, // lines + S_line = 73, // line + S_code_block = 74, // code_block + S_label_decl = 75, // label_decl + S_directive = 76, // directive + S_value = 77, // value + S_expression = 78, // expression + S_instruction = 79, // instruction + S_base_instruction = 80, // base_instruction + S_delay = 81, // delay + S_sideset = 82, // sideset + S_condition = 83, // condition + S_wait_source = 84, // wait_source + S_comma = 85, // comma + S_in_source = 86, // in_source + S_out_target = 87, // out_target + S_mov_target = 88, // mov_target + S_mov_source = 89, // mov_source + S_mov_op = 90, // mov_op + S_set_target = 91, // set_target + S_if_full = 92, // if_full + S_if_empty = 93, // if_empty + S_blocking = 94, // blocking + S_irq_modifiers = 95, // irq_modifiers + S_symbol_def = 96 // symbol_def + }; + }; + + /// (Internal) symbol kind. + typedef symbol_kind::symbol_kind_type symbol_kind_type; + + /// The number of tokens. + static const symbol_kind_type YYNTOKENS = symbol_kind::YYNTOKENS; + + /// A complete symbol. + /// + /// Expects its Base type to provide access to the symbol kind + /// via kind (). + /// + /// Provide access to semantic value and location. + template <typename Base> + struct basic_symbol : Base + { + /// Alias to Base. + typedef Base super_type; + + /// Default constructor. + basic_symbol () + : value () + , location () + {} + +#if 201103L <= YY_CPLUSPLUS + /// Move constructor. + basic_symbol (basic_symbol&& that) + : Base (std::move (that)) + , value () + , location (std::move (that.location)) + { + switch (this->kind ()) + { + case symbol_kind::S_if_full: // if_full + case symbol_kind::S_if_empty: // if_empty + case symbol_kind::S_blocking: // blocking + value.move< bool > (std::move (that.value)); + break; + + case symbol_kind::S_condition: // condition + value.move< enum condition > (std::move (that.value)); + break; + + case symbol_kind::S_in_source: // in_source + case symbol_kind::S_out_target: // out_target + case symbol_kind::S_set_target: // set_target + value.move< enum in_out_set > (std::move (that.value)); + break; + + case symbol_kind::S_irq_modifiers: // irq_modifiers + value.move< enum irq > (std::move (that.value)); + break; + + case symbol_kind::S_mov_target: // mov_target + case symbol_kind::S_mov_source: // mov_source + value.move< enum mov > (std::move (that.value)); + break; + + case symbol_kind::S_mov_op: // mov_op + value.move< enum mov_op > (std::move (that.value)); + break; + + case symbol_kind::S_INT: // "integer" + value.move< int > (std::move (that.value)); + break; + + case symbol_kind::S_instruction: // instruction + case symbol_kind::S_base_instruction: // base_instruction + value.move< std::shared_ptr<instruction> > (std::move (that.value)); + break; + + case symbol_kind::S_value: // value + case symbol_kind::S_expression: // expression + case symbol_kind::S_delay: // delay + case symbol_kind::S_sideset: // sideset + value.move< std::shared_ptr<resolvable> > (std::move (that.value)); + break; + + case symbol_kind::S_label_decl: // label_decl + case symbol_kind::S_symbol_def: // symbol_def + value.move< std::shared_ptr<symbol> > (std::move (that.value)); + break; + + case symbol_kind::S_wait_source: // wait_source + value.move< std::shared_ptr<wait_source> > (std::move (that.value)); + break; + + case symbol_kind::S_ID: // "identifier" + case symbol_kind::S_STRING: // "string" + case symbol_kind::S_NON_WS: // "text" + case symbol_kind::S_CODE_BLOCK_START: // "code block" + case symbol_kind::S_CODE_BLOCK_CONTENTS: // "%}" + case symbol_kind::S_UNKNOWN_DIRECTIVE: // UNKNOWN_DIRECTIVE + value.move< std::string > (std::move (that.value)); + break; + + default: + break; + } + + } +#endif + + /// Copy constructor. + basic_symbol (const basic_symbol& that); + + /// Constructor for valueless symbols, and symbols from each type. +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, location_type&& l) + : Base (t) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const location_type& l) + : Base (t) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, bool&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const bool& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, enum condition&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const enum condition& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, enum in_out_set&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const enum in_out_set& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, enum irq&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const enum irq& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, enum mov&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const enum mov& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, enum mov_op&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const enum mov_op& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, int&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const int& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, std::shared_ptr<instruction>&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const std::shared_ptr<instruction>& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, std::shared_ptr<resolvable>&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const std::shared_ptr<resolvable>& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, std::shared_ptr<symbol>&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const std::shared_ptr<symbol>& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, std::shared_ptr<wait_source>&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const std::shared_ptr<wait_source>& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, std::string&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const std::string& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif + + /// Destroy the symbol. + ~basic_symbol () + { + clear (); + } + + /// Destroy contents, and record that is empty. + void clear () + { + // User destructor. + symbol_kind_type yykind = this->kind (); + basic_symbol<Base>& yysym = *this; + (void) yysym; + switch (yykind) + { + default: + break; + } + + // Value type destructor. +switch (yykind) + { + case symbol_kind::S_if_full: // if_full + case symbol_kind::S_if_empty: // if_empty + case symbol_kind::S_blocking: // blocking + value.template destroy< bool > (); + break; + + case symbol_kind::S_condition: // condition + value.template destroy< enum condition > (); + break; + + case symbol_kind::S_in_source: // in_source + case symbol_kind::S_out_target: // out_target + case symbol_kind::S_set_target: // set_target + value.template destroy< enum in_out_set > (); + break; + + case symbol_kind::S_irq_modifiers: // irq_modifiers + value.template destroy< enum irq > (); + break; + + case symbol_kind::S_mov_target: // mov_target + case symbol_kind::S_mov_source: // mov_source + value.template destroy< enum mov > (); + break; + + case symbol_kind::S_mov_op: // mov_op + value.template destroy< enum mov_op > (); + break; + + case symbol_kind::S_INT: // "integer" + value.template destroy< int > (); + break; + + case symbol_kind::S_instruction: // instruction + case symbol_kind::S_base_instruction: // base_instruction + value.template destroy< std::shared_ptr<instruction> > (); + break; + + case symbol_kind::S_value: // value + case symbol_kind::S_expression: // expression + case symbol_kind::S_delay: // delay + case symbol_kind::S_sideset: // sideset + value.template destroy< std::shared_ptr<resolvable> > (); + break; + + case symbol_kind::S_label_decl: // label_decl + case symbol_kind::S_symbol_def: // symbol_def + value.template destroy< std::shared_ptr<symbol> > (); + break; + + case symbol_kind::S_wait_source: // wait_source + value.template destroy< std::shared_ptr<wait_source> > (); + break; + + case symbol_kind::S_ID: // "identifier" + case symbol_kind::S_STRING: // "string" + case symbol_kind::S_NON_WS: // "text" + case symbol_kind::S_CODE_BLOCK_START: // "code block" + case symbol_kind::S_CODE_BLOCK_CONTENTS: // "%}" + case symbol_kind::S_UNKNOWN_DIRECTIVE: // UNKNOWN_DIRECTIVE + value.template destroy< std::string > (); + break; + + default: + break; + } + + Base::clear (); + } + + /// The user-facing name of this symbol. + std::string name () const YY_NOEXCEPT + { + return parser::symbol_name (this->kind ()); + } + + /// Backward compatibility (Bison 3.6). + symbol_kind_type type_get () const YY_NOEXCEPT; + + /// Whether empty. + bool empty () const YY_NOEXCEPT; + + /// Destructive move, \a s is emptied into this. + void move (basic_symbol& s); + + /// The semantic value. + semantic_type value; + + /// The location. + location_type location; + + private: +#if YY_CPLUSPLUS < 201103L + /// Assignment operator. + basic_symbol& operator= (const basic_symbol& that); +#endif + }; + + /// Type access provider for token (enum) based symbols. + struct by_kind + { + /// Default constructor. + by_kind (); + +#if 201103L <= YY_CPLUSPLUS + /// Move constructor. + by_kind (by_kind&& that); +#endif + + /// Copy constructor. + by_kind (const by_kind& that); + + /// The symbol kind as needed by the constructor. + typedef token_kind_type kind_type; + + /// Constructor from (external) token numbers. + by_kind (kind_type t); + + /// Record that this symbol is empty. + void clear (); + + /// Steal the symbol kind from \a that. + void move (by_kind& that); + + /// The (internal) type number (corresponding to \a type). + /// \a empty when empty. + symbol_kind_type kind () const YY_NOEXCEPT; + + /// Backward compatibility (Bison 3.6). + symbol_kind_type type_get () const YY_NOEXCEPT; + + /// The symbol kind. + /// \a S_YYEMPTY when empty. + symbol_kind_type kind_; + }; + + /// Backward compatibility for a private implementation detail (Bison 3.6). + typedef by_kind by_type; + + /// "External" symbols: returned by the scanner. + struct symbol_type : basic_symbol<by_kind> + { + /// Superclass. + typedef basic_symbol<by_kind> super_type; + + /// Empty symbol. + symbol_type () {} + + /// Constructor for valueless symbols, and symbols from each type. +#if 201103L <= YY_CPLUSPLUS + symbol_type (int tok, location_type l) + : super_type(token_type (tok), std::move (l)) + { + YY_ASSERT (tok == token::TOK_END || tok == token::TOK_YYerror || tok == token::TOK_YYUNDEF || tok == token::TOK_NEWLINE || tok == token::TOK_COMMA || tok == token::TOK_COLON || tok == token::TOK_LPAREN || tok == token::TOK_RPAREN || tok == token::TOK_LBRACKET || tok == token::TOK_RBRACKET || tok == token::TOK_PLUS || tok == token::TOK_MINUS || tok == token::TOK_MULTIPLY || tok == token::TOK_DIVIDE || tok == token::TOK_OR || tok == token::TOK_AND || tok == token::TOK_XOR || tok == token::TOK_POST_DECREMENT || tok == token::TOK_NOT_EQUAL || tok == token::TOK_NOT || tok == token::TOK_REVERSE || tok == token::TOK_EQUAL || tok == token::TOK_PROGRAM || tok == token::TOK_WRAP_TARGET || tok == token::TOK_WRAP || tok == token::TOK_DEFINE || tok == token::TOK_SIDE_SET || tok == token::TOK_WORD || tok == token::TOK_ORIGIN || tok == token::TOK_LANG_OPT || tok == token::TOK_JMP || tok == token::TOK_WAIT || tok == token::TOK_IN || tok == token::TOK_OUT || tok == token::TOK_PUSH || tok == token::TOK_PULL || tok == token::TOK_MOV || tok == token::TOK_IRQ || tok == token::TOK_SET || tok == token::TOK_NOP || tok == token::TOK_PIN || tok == token::TOK_GPIO || tok == token::TOK_OSRE || tok == token::TOK_PINS || tok == token::TOK_NULL || tok == token::TOK_PINDIRS || tok == token::TOK_BLOCK || tok == token::TOK_NOBLOCK || tok == token::TOK_IFEMPTY || tok == token::TOK_IFFULL || tok == token::TOK_NOWAIT || tok == token::TOK_CLEAR || tok == token::TOK_REL || tok == token::TOK_X || tok == token::TOK_Y || tok == token::TOK_EXEC || tok == token::TOK_PC || tok == token::TOK_ISR || tok == token::TOK_OSR || tok == token::TOK_OPTIONAL || tok == token::TOK_SIDE || tok == token::TOK_STATUS || tok == token::TOK_PUBLIC); + } +#else + symbol_type (int tok, const location_type& l) + : super_type(token_type (tok), l) + { + YY_ASSERT (tok == token::TOK_END || tok == token::TOK_YYerror || tok == token::TOK_YYUNDEF || tok == token::TOK_NEWLINE || tok == token::TOK_COMMA || tok == token::TOK_COLON || tok == token::TOK_LPAREN || tok == token::TOK_RPAREN || tok == token::TOK_LBRACKET || tok == token::TOK_RBRACKET || tok == token::TOK_PLUS || tok == token::TOK_MINUS || tok == token::TOK_MULTIPLY || tok == token::TOK_DIVIDE || tok == token::TOK_OR || tok == token::TOK_AND || tok == token::TOK_XOR || tok == token::TOK_POST_DECREMENT || tok == token::TOK_NOT_EQUAL || tok == token::TOK_NOT || tok == token::TOK_REVERSE || tok == token::TOK_EQUAL || tok == token::TOK_PROGRAM || tok == token::TOK_WRAP_TARGET || tok == token::TOK_WRAP || tok == token::TOK_DEFINE || tok == token::TOK_SIDE_SET || tok == token::TOK_WORD || tok == token::TOK_ORIGIN || tok == token::TOK_LANG_OPT || tok == token::TOK_JMP || tok == token::TOK_WAIT || tok == token::TOK_IN || tok == token::TOK_OUT || tok == token::TOK_PUSH || tok == token::TOK_PULL || tok == token::TOK_MOV || tok == token::TOK_IRQ || tok == token::TOK_SET || tok == token::TOK_NOP || tok == token::TOK_PIN || tok == token::TOK_GPIO || tok == token::TOK_OSRE || tok == token::TOK_PINS || tok == token::TOK_NULL || tok == token::TOK_PINDIRS || tok == token::TOK_BLOCK || tok == token::TOK_NOBLOCK || tok == token::TOK_IFEMPTY || tok == token::TOK_IFFULL || tok == token::TOK_NOWAIT || tok == token::TOK_CLEAR || tok == token::TOK_REL || tok == token::TOK_X || tok == token::TOK_Y || tok == token::TOK_EXEC || tok == token::TOK_PC || tok == token::TOK_ISR || tok == token::TOK_OSR || tok == token::TOK_OPTIONAL || tok == token::TOK_SIDE || tok == token::TOK_STATUS || tok == token::TOK_PUBLIC); + } +#endif +#if 201103L <= YY_CPLUSPLUS + symbol_type (int tok, int v, location_type l) + : super_type(token_type (tok), std::move (v), std::move (l)) + { + YY_ASSERT (tok == token::TOK_INT); + } +#else + symbol_type (int tok, const int& v, const location_type& l) + : super_type(token_type (tok), v, l) + { + YY_ASSERT (tok == token::TOK_INT); + } +#endif +#if 201103L <= YY_CPLUSPLUS + symbol_type (int tok, std::string v, location_type l) + : super_type(token_type (tok), std::move (v), std::move (l)) + { + YY_ASSERT (tok == token::TOK_ID || tok == token::TOK_STRING || tok == token::TOK_NON_WS || tok == token::TOK_CODE_BLOCK_START || tok == token::TOK_CODE_BLOCK_CONTENTS || tok == token::TOK_UNKNOWN_DIRECTIVE); + } +#else + symbol_type (int tok, const std::string& v, const location_type& l) + : super_type(token_type (tok), v, l) + { + YY_ASSERT (tok == token::TOK_ID || tok == token::TOK_STRING || tok == token::TOK_NON_WS || tok == token::TOK_CODE_BLOCK_START || tok == token::TOK_CODE_BLOCK_CONTENTS || tok == token::TOK_UNKNOWN_DIRECTIVE); + } +#endif + }; + + /// Build a parser object. + parser (pio_assembler& pioasm_yyarg); + virtual ~parser (); + +#if 201103L <= YY_CPLUSPLUS + /// Non copyable. + parser (const parser&) = delete; + /// Non copyable. + parser& operator= (const parser&) = delete; +#endif + + /// Parse. An alias for parse (). + /// \returns 0 iff parsing succeeded. + int operator() (); + + /// Parse. + /// \returns 0 iff parsing succeeded. + virtual int parse (); + +#if YYDEBUG + /// The current debugging stream. + std::ostream& debug_stream () const YY_ATTRIBUTE_PURE; + /// Set the current debugging stream. + void set_debug_stream (std::ostream &); + + /// Type for debugging levels. + typedef int debug_level_type; + /// The current debugging level. + debug_level_type debug_level () const YY_ATTRIBUTE_PURE; + /// Set the current debugging level. + void set_debug_level (debug_level_type l); +#endif + + /// Report a syntax error. + /// \param loc where the syntax error is found. + /// \param msg a description of the syntax error. + virtual void error (const location_type& loc, const std::string& msg); + + /// Report a syntax error. + void error (const syntax_error& err); + + /// The user-facing name of the symbol whose (internal) number is + /// YYSYMBOL. No bounds checking. + static std::string symbol_name (symbol_kind_type yysymbol); + + // Implementation of make_symbol for each symbol type. +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_END (location_type l) + { + return symbol_type (token::TOK_END, std::move (l)); + } +#else + static + symbol_type + make_END (const location_type& l) + { + return symbol_type (token::TOK_END, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_YYerror (location_type l) + { + return symbol_type (token::TOK_YYerror, std::move (l)); + } +#else + static + symbol_type + make_YYerror (const location_type& l) + { + return symbol_type (token::TOK_YYerror, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_YYUNDEF (location_type l) + { + return symbol_type (token::TOK_YYUNDEF, std::move (l)); + } +#else + static + symbol_type + make_YYUNDEF (const location_type& l) + { + return symbol_type (token::TOK_YYUNDEF, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_NEWLINE (location_type l) + { + return symbol_type (token::TOK_NEWLINE, std::move (l)); + } +#else + static + symbol_type + make_NEWLINE (const location_type& l) + { + return symbol_type (token::TOK_NEWLINE, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_COMMA (location_type l) + { + return symbol_type (token::TOK_COMMA, std::move (l)); + } +#else + static + symbol_type + make_COMMA (const location_type& l) + { + return symbol_type (token::TOK_COMMA, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_COLON (location_type l) + { + return symbol_type (token::TOK_COLON, std::move (l)); + } +#else + static + symbol_type + make_COLON (const location_type& l) + { + return symbol_type (token::TOK_COLON, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_LPAREN (location_type l) + { + return symbol_type (token::TOK_LPAREN, std::move (l)); + } +#else + static + symbol_type + make_LPAREN (const location_type& l) + { + return symbol_type (token::TOK_LPAREN, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_RPAREN (location_type l) + { + return symbol_type (token::TOK_RPAREN, std::move (l)); + } +#else + static + symbol_type + make_RPAREN (const location_type& l) + { + return symbol_type (token::TOK_RPAREN, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_LBRACKET (location_type l) + { + return symbol_type (token::TOK_LBRACKET, std::move (l)); + } +#else + static + symbol_type + make_LBRACKET (const location_type& l) + { + return symbol_type (token::TOK_LBRACKET, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_RBRACKET (location_type l) + { + return symbol_type (token::TOK_RBRACKET, std::move (l)); + } +#else + static + symbol_type + make_RBRACKET (const location_type& l) + { + return symbol_type (token::TOK_RBRACKET, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_PLUS (location_type l) + { + return symbol_type (token::TOK_PLUS, std::move (l)); + } +#else + static + symbol_type + make_PLUS (const location_type& l) + { + return symbol_type (token::TOK_PLUS, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_MINUS (location_type l) + { + return symbol_type (token::TOK_MINUS, std::move (l)); + } +#else + static + symbol_type + make_MINUS (const location_type& l) + { + return symbol_type (token::TOK_MINUS, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_MULTIPLY (location_type l) + { + return symbol_type (token::TOK_MULTIPLY, std::move (l)); + } +#else + static + symbol_type + make_MULTIPLY (const location_type& l) + { + return symbol_type (token::TOK_MULTIPLY, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_DIVIDE (location_type l) + { + return symbol_type (token::TOK_DIVIDE, std::move (l)); + } +#else + static + symbol_type + make_DIVIDE (const location_type& l) + { + return symbol_type (token::TOK_DIVIDE, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_OR (location_type l) + { + return symbol_type (token::TOK_OR, std::move (l)); + } +#else + static + symbol_type + make_OR (const location_type& l) + { + return symbol_type (token::TOK_OR, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_AND (location_type l) + { + return symbol_type (token::TOK_AND, std::move (l)); + } +#else + static + symbol_type + make_AND (const location_type& l) + { + return symbol_type (token::TOK_AND, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_XOR (location_type l) + { + return symbol_type (token::TOK_XOR, std::move (l)); + } +#else + static + symbol_type + make_XOR (const location_type& l) + { + return symbol_type (token::TOK_XOR, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_POST_DECREMENT (location_type l) + { + return symbol_type (token::TOK_POST_DECREMENT, std::move (l)); + } +#else + static + symbol_type + make_POST_DECREMENT (const location_type& l) + { + return symbol_type (token::TOK_POST_DECREMENT, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_NOT_EQUAL (location_type l) + { + return symbol_type (token::TOK_NOT_EQUAL, std::move (l)); + } +#else + static + symbol_type + make_NOT_EQUAL (const location_type& l) + { + return symbol_type (token::TOK_NOT_EQUAL, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_NOT (location_type l) + { + return symbol_type (token::TOK_NOT, std::move (l)); + } +#else + static + symbol_type + make_NOT (const location_type& l) + { + return symbol_type (token::TOK_NOT, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_REVERSE (location_type l) + { + return symbol_type (token::TOK_REVERSE, std::move (l)); + } +#else + static + symbol_type + make_REVERSE (const location_type& l) + { + return symbol_type (token::TOK_REVERSE, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_EQUAL (location_type l) + { + return symbol_type (token::TOK_EQUAL, std::move (l)); + } +#else + static + symbol_type + make_EQUAL (const location_type& l) + { + return symbol_type (token::TOK_EQUAL, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_PROGRAM (location_type l) + { + return symbol_type (token::TOK_PROGRAM, std::move (l)); + } +#else + static + symbol_type + make_PROGRAM (const location_type& l) + { + return symbol_type (token::TOK_PROGRAM, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_WRAP_TARGET (location_type l) + { + return symbol_type (token::TOK_WRAP_TARGET, std::move (l)); + } +#else + static + symbol_type + make_WRAP_TARGET (const location_type& l) + { + return symbol_type (token::TOK_WRAP_TARGET, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_WRAP (location_type l) + { + return symbol_type (token::TOK_WRAP, std::move (l)); + } +#else + static + symbol_type + make_WRAP (const location_type& l) + { + return symbol_type (token::TOK_WRAP, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_DEFINE (location_type l) + { + return symbol_type (token::TOK_DEFINE, std::move (l)); + } +#else + static + symbol_type + make_DEFINE (const location_type& l) + { + return symbol_type (token::TOK_DEFINE, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_SIDE_SET (location_type l) + { + return symbol_type (token::TOK_SIDE_SET, std::move (l)); + } +#else + static + symbol_type + make_SIDE_SET (const location_type& l) + { + return symbol_type (token::TOK_SIDE_SET, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_WORD (location_type l) + { + return symbol_type (token::TOK_WORD, std::move (l)); + } +#else + static + symbol_type + make_WORD (const location_type& l) + { + return symbol_type (token::TOK_WORD, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_ORIGIN (location_type l) + { + return symbol_type (token::TOK_ORIGIN, std::move (l)); + } +#else + static + symbol_type + make_ORIGIN (const location_type& l) + { + return symbol_type (token::TOK_ORIGIN, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_LANG_OPT (location_type l) + { + return symbol_type (token::TOK_LANG_OPT, std::move (l)); + } +#else + static + symbol_type + make_LANG_OPT (const location_type& l) + { + return symbol_type (token::TOK_LANG_OPT, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_JMP (location_type l) + { + return symbol_type (token::TOK_JMP, std::move (l)); + } +#else + static + symbol_type + make_JMP (const location_type& l) + { + return symbol_type (token::TOK_JMP, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_WAIT (location_type l) + { + return symbol_type (token::TOK_WAIT, std::move (l)); + } +#else + static + symbol_type + make_WAIT (const location_type& l) + { + return symbol_type (token::TOK_WAIT, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_IN (location_type l) + { + return symbol_type (token::TOK_IN, std::move (l)); + } +#else + static + symbol_type + make_IN (const location_type& l) + { + return symbol_type (token::TOK_IN, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_OUT (location_type l) + { + return symbol_type (token::TOK_OUT, std::move (l)); + } +#else + static + symbol_type + make_OUT (const location_type& l) + { + return symbol_type (token::TOK_OUT, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_PUSH (location_type l) + { + return symbol_type (token::TOK_PUSH, std::move (l)); + } +#else + static + symbol_type + make_PUSH (const location_type& l) + { + return symbol_type (token::TOK_PUSH, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_PULL (location_type l) + { + return symbol_type (token::TOK_PULL, std::move (l)); + } +#else + static + symbol_type + make_PULL (const location_type& l) + { + return symbol_type (token::TOK_PULL, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_MOV (location_type l) + { + return symbol_type (token::TOK_MOV, std::move (l)); + } +#else + static + symbol_type + make_MOV (const location_type& l) + { + return symbol_type (token::TOK_MOV, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_IRQ (location_type l) + { + return symbol_type (token::TOK_IRQ, std::move (l)); + } +#else + static + symbol_type + make_IRQ (const location_type& l) + { + return symbol_type (token::TOK_IRQ, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_SET (location_type l) + { + return symbol_type (token::TOK_SET, std::move (l)); + } +#else + static + symbol_type + make_SET (const location_type& l) + { + return symbol_type (token::TOK_SET, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_NOP (location_type l) + { + return symbol_type (token::TOK_NOP, std::move (l)); + } +#else + static + symbol_type + make_NOP (const location_type& l) + { + return symbol_type (token::TOK_NOP, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_PIN (location_type l) + { + return symbol_type (token::TOK_PIN, std::move (l)); + } +#else + static + symbol_type + make_PIN (const location_type& l) + { + return symbol_type (token::TOK_PIN, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_GPIO (location_type l) + { + return symbol_type (token::TOK_GPIO, std::move (l)); + } +#else + static + symbol_type + make_GPIO (const location_type& l) + { + return symbol_type (token::TOK_GPIO, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_OSRE (location_type l) + { + return symbol_type (token::TOK_OSRE, std::move (l)); + } +#else + static + symbol_type + make_OSRE (const location_type& l) + { + return symbol_type (token::TOK_OSRE, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_PINS (location_type l) + { + return symbol_type (token::TOK_PINS, std::move (l)); + } +#else + static + symbol_type + make_PINS (const location_type& l) + { + return symbol_type (token::TOK_PINS, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_NULL (location_type l) + { + return symbol_type (token::TOK_NULL, std::move (l)); + } +#else + static + symbol_type + make_NULL (const location_type& l) + { + return symbol_type (token::TOK_NULL, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_PINDIRS (location_type l) + { + return symbol_type (token::TOK_PINDIRS, std::move (l)); + } +#else + static + symbol_type + make_PINDIRS (const location_type& l) + { + return symbol_type (token::TOK_PINDIRS, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_BLOCK (location_type l) + { + return symbol_type (token::TOK_BLOCK, std::move (l)); + } +#else + static + symbol_type + make_BLOCK (const location_type& l) + { + return symbol_type (token::TOK_BLOCK, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_NOBLOCK (location_type l) + { + return symbol_type (token::TOK_NOBLOCK, std::move (l)); + } +#else + static + symbol_type + make_NOBLOCK (const location_type& l) + { + return symbol_type (token::TOK_NOBLOCK, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_IFEMPTY (location_type l) + { + return symbol_type (token::TOK_IFEMPTY, std::move (l)); + } +#else + static + symbol_type + make_IFEMPTY (const location_type& l) + { + return symbol_type (token::TOK_IFEMPTY, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_IFFULL (location_type l) + { + return symbol_type (token::TOK_IFFULL, std::move (l)); + } +#else + static + symbol_type + make_IFFULL (const location_type& l) + { + return symbol_type (token::TOK_IFFULL, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_NOWAIT (location_type l) + { + return symbol_type (token::TOK_NOWAIT, std::move (l)); + } +#else + static + symbol_type + make_NOWAIT (const location_type& l) + { + return symbol_type (token::TOK_NOWAIT, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_CLEAR (location_type l) + { + return symbol_type (token::TOK_CLEAR, std::move (l)); + } +#else + static + symbol_type + make_CLEAR (const location_type& l) + { + return symbol_type (token::TOK_CLEAR, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_REL (location_type l) + { + return symbol_type (token::TOK_REL, std::move (l)); + } +#else + static + symbol_type + make_REL (const location_type& l) + { + return symbol_type (token::TOK_REL, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_X (location_type l) + { + return symbol_type (token::TOK_X, std::move (l)); + } +#else + static + symbol_type + make_X (const location_type& l) + { + return symbol_type (token::TOK_X, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_Y (location_type l) + { + return symbol_type (token::TOK_Y, std::move (l)); + } +#else + static + symbol_type + make_Y (const location_type& l) + { + return symbol_type (token::TOK_Y, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_EXEC (location_type l) + { + return symbol_type (token::TOK_EXEC, std::move (l)); + } +#else + static + symbol_type + make_EXEC (const location_type& l) + { + return symbol_type (token::TOK_EXEC, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_PC (location_type l) + { + return symbol_type (token::TOK_PC, std::move (l)); + } +#else + static + symbol_type + make_PC (const location_type& l) + { + return symbol_type (token::TOK_PC, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_ISR (location_type l) + { + return symbol_type (token::TOK_ISR, std::move (l)); + } +#else + static + symbol_type + make_ISR (const location_type& l) + { + return symbol_type (token::TOK_ISR, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_OSR (location_type l) + { + return symbol_type (token::TOK_OSR, std::move (l)); + } +#else + static + symbol_type + make_OSR (const location_type& l) + { + return symbol_type (token::TOK_OSR, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_OPTIONAL (location_type l) + { + return symbol_type (token::TOK_OPTIONAL, std::move (l)); + } +#else + static + symbol_type + make_OPTIONAL (const location_type& l) + { + return symbol_type (token::TOK_OPTIONAL, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_SIDE (location_type l) + { + return symbol_type (token::TOK_SIDE, std::move (l)); + } +#else + static + symbol_type + make_SIDE (const location_type& l) + { + return symbol_type (token::TOK_SIDE, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_STATUS (location_type l) + { + return symbol_type (token::TOK_STATUS, std::move (l)); + } +#else + static + symbol_type + make_STATUS (const location_type& l) + { + return symbol_type (token::TOK_STATUS, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_PUBLIC (location_type l) + { + return symbol_type (token::TOK_PUBLIC, std::move (l)); + } +#else + static + symbol_type + make_PUBLIC (const location_type& l) + { + return symbol_type (token::TOK_PUBLIC, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_ID (std::string v, location_type l) + { + return symbol_type (token::TOK_ID, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_ID (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_ID, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_STRING (std::string v, location_type l) + { + return symbol_type (token::TOK_STRING, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_STRING (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_STRING, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_NON_WS (std::string v, location_type l) + { + return symbol_type (token::TOK_NON_WS, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_NON_WS (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_NON_WS, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_CODE_BLOCK_START (std::string v, location_type l) + { + return symbol_type (token::TOK_CODE_BLOCK_START, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_CODE_BLOCK_START (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_CODE_BLOCK_START, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_CODE_BLOCK_CONTENTS (std::string v, location_type l) + { + return symbol_type (token::TOK_CODE_BLOCK_CONTENTS, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_CODE_BLOCK_CONTENTS (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_CODE_BLOCK_CONTENTS, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_UNKNOWN_DIRECTIVE (std::string v, location_type l) + { + return symbol_type (token::TOK_UNKNOWN_DIRECTIVE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_UNKNOWN_DIRECTIVE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_UNKNOWN_DIRECTIVE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_INT (int v, location_type l) + { + return symbol_type (token::TOK_INT, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_INT (const int& v, const location_type& l) + { + return symbol_type (token::TOK_INT, v, l); + } +#endif + + + class context + { + public: + context (const parser& yyparser, const symbol_type& yyla); + const symbol_type& lookahead () const { return yyla_; } + symbol_kind_type token () const { return yyla_.kind (); } + const location_type& location () const { return yyla_.location; } + + /// Put in YYARG at most YYARGN of the expected tokens, and return the + /// number of tokens stored in YYARG. If YYARG is null, return the + /// number of expected tokens (guaranteed to be less than YYNTOKENS). + int expected_tokens (symbol_kind_type yyarg[], int yyargn) const; + + private: + const parser& yyparser_; + const symbol_type& yyla_; + }; + + private: +#if YY_CPLUSPLUS < 201103L + /// Non copyable. + parser (const parser&); + /// Non copyable. + parser& operator= (const parser&); +#endif + + /// Check the lookahead yytoken. + /// \returns true iff the token will be eventually shifted. + bool yy_lac_check_ (symbol_kind_type yytoken) const; + /// Establish the initial context if no initial context currently exists. + /// \returns true iff the token will be eventually shifted. + bool yy_lac_establish_ (symbol_kind_type yytoken); + /// Discard any previous initial lookahead context because of event. + /// \param event the event which caused the lookahead to be discarded. + /// Only used for debbuging output. + void yy_lac_discard_ (const char* event); + + /// Stored state numbers (used for stacks). + typedef unsigned char state_type; + + /// The arguments of the error message. + int yy_syntax_error_arguments_ (const context& yyctx, + symbol_kind_type yyarg[], int yyargn) const; + + /// Generate an error message. + /// \param yyctx the context in which the error occurred. + virtual std::string yysyntax_error_ (const context& yyctx) const; + /// Compute post-reduction state. + /// \param yystate the current state + /// \param yysym the nonterminal to push on the stack + static state_type yy_lr_goto_state_ (state_type yystate, int yysym); + + /// Whether the given \c yypact_ value indicates a defaulted state. + /// \param yyvalue the value to check + static bool yy_pact_value_is_default_ (int yyvalue); + + /// Whether the given \c yytable_ value indicates a syntax error. + /// \param yyvalue the value to check + static bool yy_table_value_is_error_ (int yyvalue); + + static const signed char yypact_ninf_; + static const signed char yytable_ninf_; + + /// Convert a scanner token kind \a t to a symbol kind. + /// In theory \a t should be a token_kind_type, but character literals + /// are valid, yet not members of the token_type enum. + static symbol_kind_type yytranslate_ (int t); + + /// Convert the symbol name \a n to a form suitable for a diagnostic. + static std::string yytnamerr_ (const char *yystr); + + /// For a symbol, its name in clear. + static const char* const yytname_[]; + + + // Tables. + // YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + // STATE-NUM. + static const short yypact_[]; + + // YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + // Performed when YYTABLE does not specify something else to do. Zero + // means the default is an error. + static const signed char yydefact_[]; + + // YYPGOTO[NTERM-NUM]. + static const short yypgoto_[]; + + // YYDEFGOTO[NTERM-NUM]. + static const short yydefgoto_[]; + + // YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + // positive, shift that token. If negative, reduce the rule whose + // number is the opposite. If YYTABLE_NINF, syntax error. + static const short yytable_[]; + + static const unsigned char yycheck_[]; + + // YYSTOS[STATE-NUM] -- The (internal number of the) accessing + // symbol of state STATE-NUM. + static const signed char yystos_[]; + + // YYR1[YYN] -- Symbol number of symbol that rule YYN derives. + static const signed char yyr1_[]; + + // YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. + static const signed char yyr2_[]; + + +#if YYDEBUG + // YYRLINE[YYN] -- Source line where rule number YYN was defined. + static const short yyrline_[]; + /// Report on the debug stream that the rule \a r is going to be reduced. + virtual void yy_reduce_print_ (int r) const; + /// Print the state stack on the debug stream. + virtual void yy_stack_print_ () const; + + /// Debugging level. + int yydebug_; + /// Debug stream. + std::ostream* yycdebug_; + + /// \brief Display a symbol kind, value and location. + /// \param yyo The output stream. + /// \param yysym The symbol. + template <typename Base> + void yy_print_ (std::ostream& yyo, const basic_symbol<Base>& yysym) const; +#endif + + /// \brief Reclaim the memory associated to a symbol. + /// \param yymsg Why this token is reclaimed. + /// If null, print nothing. + /// \param yysym The symbol. + template <typename Base> + void yy_destroy_ (const char* yymsg, basic_symbol<Base>& yysym) const; + + private: + /// Type access provider for state based symbols. + struct by_state + { + /// Default constructor. + by_state () YY_NOEXCEPT; + + /// The symbol kind as needed by the constructor. + typedef state_type kind_type; + + /// Constructor. + by_state (kind_type s) YY_NOEXCEPT; + + /// Copy constructor. + by_state (const by_state& that) YY_NOEXCEPT; + + /// Record that this symbol is empty. + void clear () YY_NOEXCEPT; + + /// Steal the symbol kind from \a that. + void move (by_state& that); + + /// The symbol kind (corresponding to \a state). + /// \a symbol_kind::S_YYEMPTY when empty. + symbol_kind_type kind () const YY_NOEXCEPT; + + /// The state number used to denote an empty symbol. + /// We use the initial state, as it does not have a value. + enum { empty_state = 0 }; + + /// The state. + /// \a empty when empty. + state_type state; + }; + + /// "Internal" symbol: element of the stack. + struct stack_symbol_type : basic_symbol<by_state> + { + /// Superclass. + typedef basic_symbol<by_state> super_type; + /// Construct an empty symbol. + stack_symbol_type (); + /// Move or copy construction. + stack_symbol_type (YY_RVREF (stack_symbol_type) that); + /// Steal the contents from \a sym to build this. + stack_symbol_type (state_type s, YY_MOVE_REF (symbol_type) sym); +#if YY_CPLUSPLUS < 201103L + /// Assignment, needed by push_back by some old implementations. + /// Moves the contents of that. + stack_symbol_type& operator= (stack_symbol_type& that); + + /// Assignment, needed by push_back by other implementations. + /// Needed by some other old implementations. + stack_symbol_type& operator= (const stack_symbol_type& that); +#endif + }; + + /// A stack with random access from its top. + template <typename T, typename S = std::vector<T> > + class stack + { + public: + // Hide our reversed order. + typedef typename S::iterator iterator; + typedef typename S::const_iterator const_iterator; + typedef typename S::size_type size_type; + typedef typename std::ptrdiff_t index_type; + + stack (size_type n = 200) + : seq_ (n) + {} + +#if 201103L <= YY_CPLUSPLUS + /// Non copyable. + stack (const stack&) = delete; + /// Non copyable. + stack& operator= (const stack&) = delete; +#endif + + /// Random access. + /// + /// Index 0 returns the topmost element. + const T& + operator[] (index_type i) const + { + return seq_[size_type (size () - 1 - i)]; + } + + /// Random access. + /// + /// Index 0 returns the topmost element. + T& + operator[] (index_type i) + { + return seq_[size_type (size () - 1 - i)]; + } + + /// Steal the contents of \a t. + /// + /// Close to move-semantics. + void + push (YY_MOVE_REF (T) t) + { + seq_.push_back (T ()); + operator[] (0).move (t); + } + + /// Pop elements from the stack. + void + pop (std::ptrdiff_t n = 1) YY_NOEXCEPT + { + for (; 0 < n; --n) + seq_.pop_back (); + } + + /// Pop all elements from the stack. + void + clear () YY_NOEXCEPT + { + seq_.clear (); + } + + /// Number of elements on the stack. + index_type + size () const YY_NOEXCEPT + { + return index_type (seq_.size ()); + } + + /// Iterator on top of the stack (going downwards). + const_iterator + begin () const YY_NOEXCEPT + { + return seq_.begin (); + } + + /// Bottom of the stack. + const_iterator + end () const YY_NOEXCEPT + { + return seq_.end (); + } + + /// Present a slice of the top of a stack. + class slice + { + public: + slice (const stack& stack, index_type range) + : stack_ (stack) + , range_ (range) + {} + + const T& + operator[] (index_type i) const + { + return stack_[range_ - i]; + } + + private: + const stack& stack_; + index_type range_; + }; + + private: +#if YY_CPLUSPLUS < 201103L + /// Non copyable. + stack (const stack&); + /// Non copyable. + stack& operator= (const stack&); +#endif + /// The wrapped container. + S seq_; + }; + + + /// Stack type. + typedef stack<stack_symbol_type> stack_type; + + /// The stack. + stack_type yystack_; + /// The stack for LAC. + /// Logically, the yy_lac_stack's lifetime is confined to the function + /// yy_lac_check_. We just store it as a member of this class to hold + /// on to the memory and to avoid frequent reallocations. + /// Since yy_lac_check_ is const, this member must be mutable. + mutable std::vector<state_type> yylac_stack_; + /// Whether an initial LAC context was established. + bool yy_lac_established_; + + + /// Push a new state on the stack. + /// \param m a debug message to display + /// if null, no trace is output. + /// \param sym the symbol + /// \warning the contents of \a s.value is stolen. + void yypush_ (const char* m, YY_MOVE_REF (stack_symbol_type) sym); + + /// Push a new look ahead token on the state on the stack. + /// \param m a debug message to display + /// if null, no trace is output. + /// \param s the state + /// \param sym the symbol (for its value and location). + /// \warning the contents of \a sym.value is stolen. + void yypush_ (const char* m, state_type s, YY_MOVE_REF (symbol_type) sym); + + /// Pop \a n symbols from the stack. + void yypop_ (int n = 1); + + /// Constants. + enum + { + yylast_ = 205, ///< Last index in yytable_. + yynnts_ = 27, ///< Number of nonterminal symbols. + yyfinal_ = 96 ///< Termination state number. + }; + + + // User arguments. + pio_assembler& pioasm; + + }; + + inline + parser::symbol_kind_type + parser::yytranslate_ (int t) + { + // YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to + // TOKEN-NUM as returned by yylex. + static + const signed char + translate_table[] = + { + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69 + }; + // Last valid token kind. + const int code_max = 324; + + if (t <= 0) + return symbol_kind::S_YYEOF; + else if (t <= code_max) + return YY_CAST (symbol_kind_type, translate_table[t]); + else + return symbol_kind::S_YYUNDEF; + } + + // basic_symbol. + template <typename Base> + parser::basic_symbol<Base>::basic_symbol (const basic_symbol& that) + : Base (that) + , value () + , location (that.location) + { + switch (this->kind ()) + { + case symbol_kind::S_if_full: // if_full + case symbol_kind::S_if_empty: // if_empty + case symbol_kind::S_blocking: // blocking + value.copy< bool > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_condition: // condition + value.copy< enum condition > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_in_source: // in_source + case symbol_kind::S_out_target: // out_target + case symbol_kind::S_set_target: // set_target + value.copy< enum in_out_set > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_irq_modifiers: // irq_modifiers + value.copy< enum irq > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_mov_target: // mov_target + case symbol_kind::S_mov_source: // mov_source + value.copy< enum mov > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_mov_op: // mov_op + value.copy< enum mov_op > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_INT: // "integer" + value.copy< int > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_instruction: // instruction + case symbol_kind::S_base_instruction: // base_instruction + value.copy< std::shared_ptr<instruction> > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_value: // value + case symbol_kind::S_expression: // expression + case symbol_kind::S_delay: // delay + case symbol_kind::S_sideset: // sideset + value.copy< std::shared_ptr<resolvable> > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_label_decl: // label_decl + case symbol_kind::S_symbol_def: // symbol_def + value.copy< std::shared_ptr<symbol> > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_wait_source: // wait_source + value.copy< std::shared_ptr<wait_source> > (YY_MOVE (that.value)); + break; + + case symbol_kind::S_ID: // "identifier" + case symbol_kind::S_STRING: // "string" + case symbol_kind::S_NON_WS: // "text" + case symbol_kind::S_CODE_BLOCK_START: // "code block" + case symbol_kind::S_CODE_BLOCK_CONTENTS: // "%}" + case symbol_kind::S_UNKNOWN_DIRECTIVE: // UNKNOWN_DIRECTIVE + value.copy< std::string > (YY_MOVE (that.value)); + break; + + default: + break; + } + + } + + + + template <typename Base> + parser::symbol_kind_type + parser::basic_symbol<Base>::type_get () const YY_NOEXCEPT + { + return this->kind (); + } + + template <typename Base> + bool + parser::basic_symbol<Base>::empty () const YY_NOEXCEPT + { + return this->kind () == symbol_kind::S_YYEMPTY; + } + + template <typename Base> + void + parser::basic_symbol<Base>::move (basic_symbol& s) + { + super_type::move (s); + switch (this->kind ()) + { + case symbol_kind::S_if_full: // if_full + case symbol_kind::S_if_empty: // if_empty + case symbol_kind::S_blocking: // blocking + value.move< bool > (YY_MOVE (s.value)); + break; + + case symbol_kind::S_condition: // condition + value.move< enum condition > (YY_MOVE (s.value)); + break; + + case symbol_kind::S_in_source: // in_source + case symbol_kind::S_out_target: // out_target + case symbol_kind::S_set_target: // set_target + value.move< enum in_out_set > (YY_MOVE (s.value)); + break; + + case symbol_kind::S_irq_modifiers: // irq_modifiers + value.move< enum irq > (YY_MOVE (s.value)); + break; + + case symbol_kind::S_mov_target: // mov_target + case symbol_kind::S_mov_source: // mov_source + value.move< enum mov > (YY_MOVE (s.value)); + break; + + case symbol_kind::S_mov_op: // mov_op + value.move< enum mov_op > (YY_MOVE (s.value)); + break; + + case symbol_kind::S_INT: // "integer" + value.move< int > (YY_MOVE (s.value)); + break; + + case symbol_kind::S_instruction: // instruction + case symbol_kind::S_base_instruction: // base_instruction + value.move< std::shared_ptr<instruction> > (YY_MOVE (s.value)); + break; + + case symbol_kind::S_value: // value + case symbol_kind::S_expression: // expression + case symbol_kind::S_delay: // delay + case symbol_kind::S_sideset: // sideset + value.move< std::shared_ptr<resolvable> > (YY_MOVE (s.value)); + break; + + case symbol_kind::S_label_decl: // label_decl + case symbol_kind::S_symbol_def: // symbol_def + value.move< std::shared_ptr<symbol> > (YY_MOVE (s.value)); + break; + + case symbol_kind::S_wait_source: // wait_source + value.move< std::shared_ptr<wait_source> > (YY_MOVE (s.value)); + break; + + case symbol_kind::S_ID: // "identifier" + case symbol_kind::S_STRING: // "string" + case symbol_kind::S_NON_WS: // "text" + case symbol_kind::S_CODE_BLOCK_START: // "code block" + case symbol_kind::S_CODE_BLOCK_CONTENTS: // "%}" + case symbol_kind::S_UNKNOWN_DIRECTIVE: // UNKNOWN_DIRECTIVE + value.move< std::string > (YY_MOVE (s.value)); + break; + + default: + break; + } + + location = YY_MOVE (s.location); + } + + // by_kind. + inline + parser::by_kind::by_kind () + : kind_ (symbol_kind::S_YYEMPTY) + {} + +#if 201103L <= YY_CPLUSPLUS + inline + parser::by_kind::by_kind (by_kind&& that) + : kind_ (that.kind_) + { + that.clear (); + } +#endif + + inline + parser::by_kind::by_kind (const by_kind& that) + : kind_ (that.kind_) + {} + + inline + parser::by_kind::by_kind (token_kind_type t) + : kind_ (yytranslate_ (t)) + {} + + inline + void + parser::by_kind::clear () + { + kind_ = symbol_kind::S_YYEMPTY; + } + + inline + void + parser::by_kind::move (by_kind& that) + { + kind_ = that.kind_; + that.clear (); + } + + inline + parser::symbol_kind_type + parser::by_kind::kind () const YY_NOEXCEPT + { + return kind_; + } + + inline + parser::symbol_kind_type + parser::by_kind::type_get () const YY_NOEXCEPT + { + return this->kind (); + } + +} // yy + + + + +#endif // !YY_YY_HOME_GRAHAM_DEV_MU_PICO_SDK_TOOLS_PIOASM_GEN_PARSER_HPP_INCLUDED diff --git a/circuitpython/ports/raspberrypi/sdk/tools/pioasm/hex_output.cpp b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/hex_output.cpp new file mode 100644 index 0000000..39dd0fa --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/hex_output.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "output_format.h" +#include <iostream> + +struct hex_output : public output_format { + struct factory { + factory() { + output_format::add(new hex_output()); + } + }; + + hex_output() : output_format("hex") {} + + std::string get_description() { + return "Raw hex output (only valid for single program inputs)"; + } + + virtual int output(std::string destination, std::vector<std::string> output_options, + const compiled_source &source) { + FILE *out = open_single_output(destination); + if (!out) return 1; + + if (source.programs.size() > 1) { + // todo don't have locations any more! + std::cerr << "error: hex output only supports a single program input\n"; + return 1; + } + for (const auto &i : source.programs[0].instructions) { + fprintf(out, "%04x\n", i); + } + if (out != stdout) { fclose(out); } + return 0; + } +}; + +static hex_output::factory creator; diff --git a/circuitpython/ports/raspberrypi/sdk/tools/pioasm/lexer.ll b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/lexer.ll new file mode 100644 index 0000000..939b06f --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/lexer.ll @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +%{ /* -*- C++ -*- */ +# include <cerrno> +# include <climits> +# include <cstdlib> +# include <cstring> +# include <string> +# include "pio_assembler.h" +# include "parser.hpp" + +#ifdef _MSC_VER +#pragma warning(disable : 4996) // fopen +#endif + +%} + +%option noyywrap nounput noinput batch debug never-interactive case-insensitive noline + +%{ + yy::parser::symbol_type make_INT(const std::string &s, const yy::parser::location_type& loc); + yy::parser::symbol_type make_HEX(const std::string &s, const yy::parser::location_type& loc); + yy::parser::symbol_type make_BINARY(const std::string &s, const yy::parser::location_type& loc); +%} + +blank [ \t] +whitesp {blank}+ + +comment (";"|"//")[^\n]* + +digit [0-9] +id [a-zA-Z_][a-zA-Z0-9_]* + +binary "0b"[01]+ +int {digit}+ +hex "0x"[0-9a-fA-F]+ +directive \.{id} + +output_fmt [^%\n]+ + +%{ + // Code run each time a pattern is matched. + # define YY_USER_ACTION loc.columns (yyleng); +%} + +%x code_block +%x c_comment +%x lang_opt + +%% + std::string code_block_contents; + yy::location code_block_start; +%{ + // A handy shortcut to the location held by the pio_assembler. + yy::location& loc = pioasm.location; + // Code run each time yylex is called. + loc.step(); +%} + +{blank}+ loc.step(); +\n+ { auto loc_newline = loc; loc_newline.end = loc_newline.begin; loc.lines(yyleng); loc.step(); return yy::parser::make_NEWLINE(loc_newline); } + +"%"{blank}*{output_fmt}{blank}*"{" { + BEGIN(code_block); + code_block_contents = ""; + code_block_start = loc; + std::string tmp(yytext); + tmp = tmp.substr(1, tmp.length() - 2); + tmp = tmp.erase(0, tmp.find_first_not_of(" \t")); + tmp = tmp.erase(tmp.find_last_not_of(" \t") + 1); + return yy::parser::make_CODE_BLOCK_START( tmp, loc); + } +<code_block>{ + {blank}+ loc.step(); + \n+ { auto loc_newline = loc; loc_newline.end = loc_newline.begin; loc.lines(yyleng); loc.step(); } + "%}" { BEGIN(INITIAL); auto loc2 = loc; loc2.begin = code_block_start.begin; return yy::parser::make_CODE_BLOCK_CONTENTS(code_block_contents, loc2); } + .* { code_block_contents += std::string(yytext) + "\n"; } +} + +<c_comment>{ + {blank}+ loc.step(); + "*/" { BEGIN(INITIAL); } + "*" { } + [^\n\*]* { } + \n+ { auto loc_newline = loc; loc_newline.end = loc_newline.begin; loc.lines(yyleng); loc.step(); } +} + +<lang_opt>{ +\"[^\n]*\" return yy::parser::make_STRING(yytext, loc); +{blank}+ loc.step(); +"=" return yy::parser::make_EQUAL(loc); +{int} return make_INT(yytext, loc); +{hex} return make_HEX(yytext, loc); +{binary} return make_BINARY(yytext, loc); +[^ \t\n\"=]+ return yy::parser::make_NON_WS(yytext, loc); +\n+ { BEGIN(INITIAL); auto loc_newline = loc; loc_newline.end = loc_newline.begin; loc.lines(yyleng); loc.step(); return yy::parser::make_NEWLINE(loc_newline); } +. { throw yy::parser::syntax_error(loc, "invalid character: " + std::string(yytext)); } +} + +"/*" { BEGIN(c_comment); } +"," return yy::parser::make_COMMA(loc); +"::" return yy::parser::make_REVERSE(loc); +":" return yy::parser::make_COLON(loc); +"[" return yy::parser::make_LBRACKET(loc); +"]" return yy::parser::make_RBRACKET(loc); +"(" return yy::parser::make_LPAREN(loc); +")" return yy::parser::make_RPAREN(loc); +"+" return yy::parser::make_PLUS(loc); +"--" return yy::parser::make_POST_DECREMENT(loc); +"−−" return yy::parser::make_POST_DECREMENT(loc); +"-" return yy::parser::make_MINUS(loc); +"*" return yy::parser::make_MULTIPLY(loc); +"/" return yy::parser::make_DIVIDE(loc); +"|" return yy::parser::make_OR(loc); +"&" return yy::parser::make_AND(loc); +"^" return yy::parser::make_XOR(loc); +"!=" return yy::parser::make_NOT_EQUAL(loc); +"!" return yy::parser::make_NOT(loc); +"~" return yy::parser::make_NOT(loc); + +".program" return yy::parser::make_PROGRAM(loc); +".wrap_target" return yy::parser::make_WRAP_TARGET(loc); +".wrap" return yy::parser::make_WRAP(loc); +".word" return yy::parser::make_WORD(loc); +".define" return yy::parser::make_DEFINE(loc); +".side_set" return yy::parser::make_SIDE_SET(loc); +".origin" return yy::parser::make_ORIGIN(loc); +".lang_opt" { BEGIN(lang_opt); return yy::parser::make_LANG_OPT(loc); } +{directive} return yy::parser::make_UNKNOWN_DIRECTIVE(yytext, loc); + +"JMP" return yy::parser::make_JMP(loc); +"WAIT" return yy::parser::make_WAIT(loc); +"IN" return yy::parser::make_IN(loc); +"OUT" return yy::parser::make_OUT(loc); +"PUSH" return yy::parser::make_PUSH(loc); +"PULL" return yy::parser::make_PULL(loc); +"MOV" return yy::parser::make_MOV(loc); +"IRQ" return yy::parser::make_IRQ(loc); +"SET" return yy::parser::make_SET(loc); +"NOP" return yy::parser::make_NOP(loc); + +"PUBLIC" return yy::parser::make_PUBLIC(loc); + +"OPTIONAL" return yy::parser::make_OPTIONAL(loc); +"OPT" return yy::parser::make_OPTIONAL(loc); +"SIDE" return yy::parser::make_SIDE(loc); +"SIDESET" return yy::parser::make_SIDE(loc); +"SIDE_SET" return yy::parser::make_SIDE(loc); +"PIN" return yy::parser::make_PIN(loc); +"GPIO" return yy::parser::make_GPIO(loc); +"OSRE" return yy::parser::make_OSRE(loc); + +"PINS" return yy::parser::make_PINS(loc); +"NULL" return yy::parser::make_NULL(loc); +"PINDIRS" return yy::parser::make_PINDIRS(loc); +"X" return yy::parser::make_X(loc); +"Y" return yy::parser::make_Y(loc); +"PC" return yy::parser::make_PC(loc); +"EXEC" return yy::parser::make_EXEC(loc); +"ISR" return yy::parser::make_ISR(loc); +"OSR" return yy::parser::make_OSR(loc); +"STATUS" return yy::parser::make_STATUS(loc); + +"BLOCK" return yy::parser::make_BLOCK(loc); +"NOBLOCK" return yy::parser::make_NOBLOCK(loc); +"IFFULL" return yy::parser::make_IFFULL(loc); +"IFEMPTY" return yy::parser::make_IFEMPTY(loc); +"REL" return yy::parser::make_REL(loc); + +"CLEAR" return yy::parser::make_CLEAR(loc); +"NOWAIT" return yy::parser::make_NOWAIT(loc); + +"ONE" return yy::parser::make_INT(1, loc); +"ZERO" return yy::parser::make_INT(0, loc); + +<<EOF>> return yy::parser::make_END(loc); + +{int} return make_INT(yytext, loc); +{hex} return make_HEX(yytext, loc); +{binary} return make_BINARY(yytext, loc); + +{id} return yy::parser::make_ID(yytext, loc); + +{comment} { } + +. { throw yy::parser::syntax_error(loc, "invalid character: " + std::string(yytext)); } + +%% + +yy::parser::symbol_type make_INT(const std::string &s, const yy::parser::location_type& loc) +{ + errno = 0; + long n = strtol (s.c_str(), NULL, 10); + if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE)) + throw yy::parser::syntax_error (loc, "integer is out of range: " + s); + return yy::parser::make_INT((int) n, loc); +} + +yy::parser::symbol_type make_HEX(const std::string &s, const yy::parser::location_type& loc) +{ + errno = 0; + long n = strtol (s.c_str() + 2, NULL, 16); + if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE)) + throw yy::parser::syntax_error (loc, "hex is out of range: " + s); + return yy::parser::make_INT((int) n, loc); +} + +yy::parser::symbol_type make_BINARY(const std::string &s, const yy::parser::location_type& loc) +{ + errno = 0; + long n = strtol (s.c_str()+2, NULL, 2); + if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE)) + throw yy::parser::syntax_error (loc, "binary is out of range: " + s); + return yy::parser::make_INT((int) n, loc); +} + +void pio_assembler::scan_begin () +{ + yy_flex_debug = false; + if (source.empty () || source == "-") + yyin = stdin; + else if (!(yyin = fopen (source.c_str (), "r"))) + { + std::cerr << "cannot open " << source << ": " << strerror(errno) << '\n'; + exit (EXIT_FAILURE); + } +} + +void pio_assembler::scan_end () +{ + fclose (yyin); +} diff --git a/circuitpython/ports/raspberrypi/sdk/tools/pioasm/main.cpp b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/main.cpp new file mode 100644 index 0000000..e7ff686 --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/main.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <iostream> +#include "pio_assembler.h" + +#define DEFAULT_OUTPUT_FORMAT "c-sdk" + +void usage() { + std::cerr << "usage: pioasm <options> <input> (<output>)\n\n"; + std::cerr << "Assemble file of PIO program(s) for use in applications.\n"; + std::cerr << " <input> the input filename\n"; + std::cerr << " <output> the output filename (or filename prefix if the output format produces multiple outputs).\n"; + std::cerr << " if not specified, a single output will be written to stdout\n"; + std::cerr << "\n"; + std::cerr << "options:\n"; + std::cerr << " -o <output_format> select output_format (default '" << DEFAULT_OUTPUT_FORMAT << "'); available options are:\n"; + for(const auto& f : output_format::all()) { + std::cerr << " " << f->name << std::endl; + std::cerr << " " << f->get_description() << std::endl; + } + std::cerr << " -p <output_param> add a parameter to be passed to the output format generator" << std::endl; + std::cerr << " -?, --help print this help and exit\n"; +} + +int main(int argc, char *argv[]) { + int res = 0; + pio_assembler pioasm; + std::string format(DEFAULT_OUTPUT_FORMAT); + const char *input = nullptr; + const char *output = nullptr; + std::vector<std::string> options; + int i = 1; + for (; !res && i < argc; i++) { + if (argv[i][0] != '-') break; + if (argv[i] == std::string("-o")) { + if (++i < argc) { + format = argv[i]; + } else { + std::cerr << "error: -o requires format value" << std::endl; + res = 1; + } + } else if (argv[i] == std::string("-p")) { + if (++i < argc) { + options.emplace_back(argv[i]); + } else { + std::cerr << "error: -p requires parameter value" << std::endl; + res = 1; + } + } else if (argv[i] == std::string("-?") || argv[i] == std::string("--help")) { + usage(); + return 1; + } else { + std::cerr << "error: unknown option " << argv[i] << std::endl; + res = 1; + } + } + if (!res) { + if (i != argc) { + input = argv[i++]; + } else { + std::cerr << "error: expected input filename\n"; + res = 1; + } + } + if (!res) { + if (i != argc) { + output = argv[i++]; + } else { + output = "-"; + } + } + if (!res && i != argc) { + std::cerr << "unexpected command line argument " << argv[i] << std::endl; + res = 1; + } + std::shared_ptr<output_format> oformat; + if (!res) { + const auto& e = std::find_if(output_format::all().begin(), output_format::all().end(), + [&](const std::shared_ptr<output_format> &f) { + return f->name == format; + }); + if (e == output_format::all().end()) { + std::cerr << "error: unknown output format '" << format << "'" << std::endl; + res = 1; + } else { + oformat = *e; + } + } + if (res) { + std::cerr << std::endl; + usage(); + } else { + res = pioasm.generate(oformat, input, output, options); + } + return res; +}
\ No newline at end of file diff --git a/circuitpython/ports/raspberrypi/sdk/tools/pioasm/output_format.h b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/output_format.h new file mode 100644 index 0000000..2ba899d --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/output_format.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _OUTPUT_FORMAT_H +#define _OUTPUT_FORMAT_H + +#include <vector> +#include <map> +#include <string> +#include <memory> + +typedef unsigned int uint; + +// can't use optional because we want to support older compilers +template<typename T> +struct simple_optional { + T value; + T default_value; + bool specified; + + simple_optional() : default_value(), specified(false) {} + + simple_optional(const T &value) : value(value), specified(true) {} + + simple_optional<T> &operator=(const T &v) { + value = v; + specified = true; + return *this; + } + + operator bool() = delete; // confusing + const T &get() const { return specified ? value : default_value; } + + bool is_specified() const { return specified; } + + static simple_optional<T> with_default(const T &default_value) { + simple_optional<T> rc; + rc.default_value = default_value; + return rc; + } +}; + +typedef simple_optional<int> optional_int; +typedef simple_optional<bool> optional_bool; + +struct compiled_source { + struct symbol { + std::string name; + int value; + bool is_label; + + symbol(std::string name, int value, bool is_label) : name(std::move(name)), value(value), is_label(is_label) {} + }; + + struct program { + std::string name; + optional_int origin = optional_int::with_default(-1); + optional_int sideset_bits_including_opt; + bool sideset_opt = false; + bool sideset_pindirs = false; + int wrap; + int wrap_target; + std::vector<uint> instructions; + std::vector<symbol> symbols; // public only + std::map<std::string, std::vector<std::string>> code_blocks; + std::map<std::string, std::vector<std::pair<std::string,std::string>>> lang_opts; + + // todo can't have wrap at -1 + program(std::string name) : name(std::move(name)) {} + }; + + std::vector<symbol> global_symbols; // public only + std::vector<program> programs; +}; + +struct output_format { + static std::string default_name; + + std::string name; + + static void add(output_format *lang) { + all().push_back(std::shared_ptr<output_format>(lang)); + } + + virtual int output(std::string destination, std::vector<std::string> output_options, + const compiled_source &source) = 0; + + virtual std::string get_description() = 0; + + FILE *open_single_output(std::string destination); + virtual ~output_format() = default; + + static std::vector<std::shared_ptr<output_format>>& all() { + static std::vector<std::shared_ptr<output_format>> output_formats; + return output_formats; + } +protected: + output_format(std::string name) : name(std::move(name)) {} +}; + +#endif
\ No newline at end of file diff --git a/circuitpython/ports/raspberrypi/sdk/tools/pioasm/parser.yy b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/parser.yy new file mode 100644 index 0000000..467ca89 --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/parser.yy @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +%skeleton "lalr1.cc" /* -*- C++ -*- */ +%require "3.4.2" +%defines + +%define api.token.constructor +%define api.value.type variant +/*%define parse.assert*/ +%define api.location.file "location.h" +%define parse.lac full +/* define parse.trace*/ +%define parse.error verbose +%no-lines +%locations + +%code requires { + #include <string> + #include <fstream> + #include <sstream> + #include "pio_types.h" + struct pio_assembler; + + #ifdef _MSC_VER + #pragma warning(disable : 4065) // default only switch statement + #endif +} + +// The parsing context. +%param { pio_assembler& pioasm } + +%code { + #include "pio_assembler.h" + #ifdef _MSC_VER + #pragma warning(disable : 4244) // possible loss of data (valid warning, but there is a software check / missing cast) + #endif +} + +%define api.token.prefix {TOK_} + +%token + END 0 "end of file" + + NEWLINE "end of line" + COMMA "," + COLON ":" + + LPAREN "(" + RPAREN ")" + LBRACKET "[" + RBRACKET "]" + PLUS "+" + MINUS "-" + MULTIPLY "*" + DIVIDE "/" + OR "|" + AND "&" + XOR "^" + POST_DECREMENT "--" + NOT_EQUAL "!=" + NOT "!" + REVERSE "::" + EQUAL "=" + + PROGRAM ".program" + WRAP_TARGET ".wrap_target" + WRAP ".wrap" + DEFINE ".define" + SIDE_SET ".side_set" + WORD ".word" + ORIGIN ".origin" + LANG_OPT ".lang_opt" + + JMP "jmp" + WAIT "wait" + IN "in" + OUT "out" + PUSH "push" + PULL "pull" + MOV "mov" + IRQ "irq" + SET "set" + NOP "nop" + + PIN "pin" + GPIO "gpio" + OSRE "osre" + + PINS "pins" + NULL "null" + PINDIRS "pindirs" + BLOCK "block" + NOBLOCK "noblock" + IFEMPTY "ifempty" + IFFULL "iffull" + NOWAIT "nowait" + CLEAR "clear" + REL "rel" + X "x" + Y "y" + EXEC "exec" + PC "pc" + ISR "isr" + OSR "osr" + OPTIONAL "opt" + SIDE "side" + STATUS "status" + PUBLIC "public" +; + +%token + <std::string> ID "identifier" + <std::string> STRING "string" + <std::string> NON_WS "text" + <std::string> CODE_BLOCK_START "code block" + <std::string> CODE_BLOCK_CONTENTS "%}" // bit ugly but if there is no end this is what we will be missing + <std::string> UNKNOWN_DIRECTIVE + <int> INT "integer" +; + + +%left REVERSE +%left PLUS MINUS +%left MULTIPLY DIVIDE +%left AND OR XOR + +%printer { yyo << "..."; } <*>; + +%% + +file: + lines END { if (pioasm.error_count || pioasm.write_output()) YYABORT; } + ; + +lines: + line + | lines NEWLINE line; + +line: + PROGRAM ID { if (!pioasm.add_program(@$, $2)) { std::stringstream msg; msg << "program " << $2 << " already exists"; error(@$, msg.str()); abort(); } } + | directive + | instruction { pioasm.get_current_program(@1, "instruction").add_instruction($1); } + | label_decl instruction { auto &p = pioasm.get_current_program(@2, "instruction"); p.add_label($1); p.add_instruction($2); } + | label_decl { pioasm.get_current_program(@1, "label").add_label($1); } + | code_block + | %empty + | error { if (pioasm.error_count > 6) { std::cerr << "\ntoo many errors; aborting.\n"; YYABORT; } } + ; + +code_block: + CODE_BLOCK_START CODE_BLOCK_CONTENTS { std::string of = $1; if (of.empty()) of = output_format::default_name; pioasm.get_current_program(@$, "code block", false, false).add_code_block( code_block(@$, of, $2)); } + +%type <std::shared_ptr<symbol>> label_decl; +label_decl: + symbol_def COLON { $1->is_label = true; $$ = $1; } + +directive: + DEFINE symbol_def expression { $2->is_label = false; $2->value = $3; pioasm.get_current_program(@1, ".define", false, false).add_symbol($2); } + | ORIGIN value { pioasm.get_current_program(@1, ".origin", true).set_origin(@$, $2); } + | SIDE_SET value OPTIONAL PINDIRS { pioasm.get_current_program(@1, ".side_set", true).set_sideset(@$, $2, true, true); } + | SIDE_SET value OPTIONAL { pioasm.get_current_program(@1, ".side_set", true).set_sideset(@$, $2, true, false); } + | SIDE_SET value PINDIRS { pioasm.get_current_program(@1, ".side_set", true).set_sideset(@$, $2, false, true); } + | SIDE_SET value { pioasm.get_current_program(@1, ".side_set", true).set_sideset(@$, $2, false, false); } + | WRAP_TARGET { pioasm.get_current_program(@1, ".wrap_target").set_wrap_target(@$); } + | WRAP { pioasm.get_current_program(@1, ".wrap").set_wrap(@$); } + | WORD value { pioasm.get_current_program(@1, "instruction").add_instruction(std::shared_ptr<instruction>(new instr_word(@$, $2))); } + | LANG_OPT NON_WS NON_WS EQUAL INT { pioasm.get_current_program(@1, ".lang_opt").add_lang_opt($2, $3, std::to_string($5)); } + | LANG_OPT NON_WS NON_WS EQUAL STRING { pioasm.get_current_program(@1, ".lang_opt").add_lang_opt($2, $3, $5); } + | LANG_OPT NON_WS NON_WS EQUAL NON_WS { pioasm.get_current_program(@1, ".lang_opt").add_lang_opt($2, $3, $5); } + | LANG_OPT error { error(@$, "expected format is .lang_opt language option_name = option_value"); } + | UNKNOWN_DIRECTIVE { std::stringstream msg; msg << "unknown directive " << $1; throw syntax_error(@$, msg.str()); } + ; + +/* value is a more limited top level expression... requiring parenthesis */ +%type <std::shared_ptr<resolvable>> value; +value: INT { $$ = resolvable_int(@$, $1); } + | ID { $$ = std::shared_ptr<resolvable>(new name_ref(@$, $1)); } + | LPAREN expression RPAREN { $$ = $2; } + +%type <std::shared_ptr<resolvable>> expression; +expression: + value + | expression PLUS expression { $$ = std::shared_ptr<binary_operation>(new binary_operation(@$, binary_operation::add, $1, $3)); } + | expression MINUS expression { $$ = std::shared_ptr<binary_operation>(new binary_operation(@$, binary_operation::subtract, $1, $3)); } + | expression MULTIPLY expression { $$ = std::shared_ptr<binary_operation>(new binary_operation(@$, binary_operation::multiply, $1, $3)); } + | expression DIVIDE expression { $$ = std::shared_ptr<binary_operation>(new binary_operation(@$, binary_operation::divide, $1, $3)); } + | expression OR expression { $$ = std::shared_ptr<binary_operation>(new binary_operation(@$, binary_operation::or_, $1, $3)); } + | expression AND expression { $$ = std::shared_ptr<binary_operation>(new binary_operation(@$, binary_operation::and_, $1, $3)); } + | expression XOR expression { $$ = std::shared_ptr<binary_operation>(new binary_operation(@$, binary_operation::xor_, $1, $3)); } + | MINUS expression { $$ = std::shared_ptr<unary_operation>(new unary_operation(@$, unary_operation::negate, $2)); } + | REVERSE expression { $$ = std::shared_ptr<unary_operation>(new unary_operation(@$, unary_operation::reverse, $2)); } + +%type <std::shared_ptr<instruction>> instruction; +instruction: + base_instruction sideset delay { $$ = $1; $$->sideset = $2; $$->delay = $3; } + | base_instruction delay sideset { $$ = $1; $$->delay = $2; $$->sideset = $3; } + | base_instruction sideset { $$ = $1; $$->sideset = $2; $$->delay = resolvable_int(@$, 0); } + | base_instruction delay { $$ = $1; $$->delay = $2; } + | base_instruction { $$ = $1; $$->delay = resolvable_int(@$, 0); } + +%type <std::shared_ptr<instruction>> base_instruction; +base_instruction: + NOP { $$ = std::shared_ptr<instruction>(new instr_nop(@$)); } + | JMP condition comma expression { $$ = std::shared_ptr<instruction>(new instr_jmp(@$, $2, $4)); } + | WAIT value wait_source { $$ = std::shared_ptr<instruction>(new instr_wait(@$, $2, $3)); } + | WAIT value COMMA value { std::stringstream msg; location l; l.begin = @2.end; l.end = @3.end; msg << "expected irq, gpio or pin after the polarity value and before the \",\""; throw yy::parser::syntax_error(l, msg.str()); } + | WAIT wait_source { $$ = std::shared_ptr<instruction>(new instr_wait(@$, resolvable_int(@$, 1), $2)); } + | IN in_source comma value { $$ = std::shared_ptr<instruction>(new instr_in(@$, $2, $4)); } + | OUT out_target comma value { $$ = std::shared_ptr<instruction>(new instr_out(@$, $2, $4)); } + | PUSH if_full blocking { $$ = std::shared_ptr<instruction>(new instr_push(@$, $2, $3)); } + | PULL if_empty blocking { $$ = std::shared_ptr<instruction>(new instr_pull(@$, $2, $3)); } + | MOV mov_target comma mov_op mov_source { $$ = std::shared_ptr<instruction>(new instr_mov(@$, $2, $5, $4)); } + | IRQ irq_modifiers value REL { $$ = std::shared_ptr<instruction>(new instr_irq(@$, $2, $3, true)); } + | IRQ irq_modifiers value { $$ = std::shared_ptr<instruction>(new instr_irq(@$, $2, $3)); } + | SET set_target comma value { $$ = std::shared_ptr<instruction>(new instr_set(@$, $2, $4)); } +; + +%type <std::shared_ptr<resolvable>> delay; +delay: + LBRACKET expression RBRACKET { $$ = $2; } + +%type <std::shared_ptr<resolvable>> sideset; +sideset: + SIDE value { $$ = $2; } + +%type <enum condition> condition; +condition: + NOT X { $$ = condition::xz; } + | X POST_DECREMENT { $$ = condition::xnz__; } + | NOT Y { $$ = condition::yz; } + | Y POST_DECREMENT { $$ = condition::ynz__; } + | X NOT_EQUAL Y { $$ = condition::xney; } + | PIN { $$ = condition::pin; } + | NOT OSRE { $$ = condition::osrez; } + | %empty { $$ = condition::al; } + +%type <std::shared_ptr<wait_source>> wait_source; +wait_source: + IRQ comma value REL { $$ = std::shared_ptr<wait_source>(new wait_source(wait_source::irq, $3, true)); } + | IRQ comma value { $$ = std::shared_ptr<wait_source>(new wait_source(wait_source::irq, $3, false)); } + | GPIO comma value { $$ = std::shared_ptr<wait_source>(new wait_source(wait_source::gpio, $3)); } + | PIN comma value { $$ = std::shared_ptr<wait_source>(new wait_source(wait_source::pin, $3)); } + +comma: COMMA | %empty /* not a huge fan of forcing commas */ + +%type <enum in_out_set> in_source; +in_source: PINS { $$ = in_out_set::in_out_set_pins; } + | X { $$ = in_out_set::in_out_set_x; } + | Y { $$ = in_out_set::in_out_set_y; } + | NULL { $$ = in_out_set::in_out_null; } + | ISR { $$ = in_out_set::in_out_isr; } + | OSR { $$ = in_out_set::in_osr; } + | STATUS { $$ = in_out_set::in_status; } + +%type <enum in_out_set> out_target; +out_target: PINS { $$ = in_out_set::in_out_set_pins; } + | X { $$ = in_out_set::in_out_set_x; } + | Y { $$ = in_out_set::in_out_set_y; } + | NULL { $$ = in_out_set::in_out_null; } + | PINDIRS { $$ = in_out_set::in_out_set_pindirs; } + | ISR { $$ = in_out_set::in_out_isr; } + | PC { $$ = in_out_set::out_set_pc; } + | EXEC { $$ = in_out_set::out_exec; } + +%type <enum mov> mov_target; +mov_target: PINS { $$ = mov::pins; } + | X { $$ = mov::x; } + | Y { $$ = mov::y; } + | EXEC { $$ = mov::exec; } + | PC { $$ = mov::pc; } + | ISR { $$ = mov::isr; } + | OSR { $$ = mov::osr; } + +%type <enum mov> mov_source; +mov_source: PINS { $$ = mov::pins; } + | X { $$ = mov::x; } + | Y { $$ = mov::y; } + | NULL { $$ = mov::null; } + | STATUS { $$ = mov::status; } + | ISR { $$ = mov::isr; } + | OSR { $$ = mov::osr; } + +%type <enum mov_op> mov_op; +mov_op: + NOT { $$ = mov_op::invert; } + | REVERSE { $$ = mov_op::bit_reverse; } + | %empty { $$ = mov_op::none; } + +%type <enum in_out_set> set_target; +set_target: + PINS { $$ = in_out_set::in_out_set_pins; } + | X { $$ = in_out_set::in_out_set_x; } + | Y { $$ = in_out_set::in_out_set_y; } + | PINDIRS { $$ = in_out_set::in_out_set_pindirs; } + +%type <bool> if_full; +if_full: + IFFULL { $$ = true; } + | %empty { $$ = false; } + +%type <bool> if_empty; +if_empty: + IFEMPTY { $$ = true; } + | %empty { $$ = false; } + +%type <bool> blocking; +blocking: + BLOCK { $$ = true; } + | NOBLOCK { $$ = false; } + | %empty { $$ = true; } + +%type <enum irq> irq_modifiers; +irq_modifiers: + CLEAR { $$ = irq::clear; } + | WAIT { $$ = irq::set_wait; } + | NOWAIT { $$ = irq::set; } + | SET { $$ = irq::set; } + | %empty { $$ = irq::set; } + +%type <std::shared_ptr<symbol>> symbol_def; +symbol_def: + ID { $$ = std::shared_ptr<symbol>(new symbol(@$, $1)); } + | PUBLIC ID { $$ = std::shared_ptr<symbol>(new symbol(@$, $2, true)); } + | MULTIPLY ID { $$ = std::shared_ptr<symbol>(new symbol(@$, $2, true)); } + +%% +void yy::parser::error(const location_type& l, const std::string& m) +{ + if (l.begin.filename) { + std::cerr << l << ": " << m << '\n'; + pioasm.error_count++; + if (l.begin.line == l.end.line && *l.begin.filename == *l.end.filename) { + std::ifstream file(l.begin.filename->c_str()); + std::string line; + for(int i = 0; i < l.begin.line; ++i) { + std::getline(file, line); + } + fprintf(stderr, "%5d | %s\n", l.begin.line, line.c_str()); + fprintf(stderr, "%5s | %*s", "", l.begin.column, "^"); + for (int i = l.begin.column; i < l.end.column - 1; i++) { + putc ('~', stderr); + } + putc ('\n', stderr); + } + } else { + std::cerr << m << '\n'; + } +} + diff --git a/circuitpython/ports/raspberrypi/sdk/tools/pioasm/pio_assembler.cpp b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/pio_assembler.cpp new file mode 100644 index 0000000..469d733 --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/pio_assembler.cpp @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <cstdio> +#include <iterator> +#include "pio_assembler.h" +#include "parser.hpp" + +#ifdef _MSC_VER +#pragma warning(disable : 4996) // fopen +#endif + +using syntax_error = yy::parser::syntax_error; + +std::string output_format::default_name = "c-sdk"; + +pio_assembler::pio_assembler() { +} + +int pio_assembler::generate(std::shared_ptr<output_format> _format, const std::string &_source, + const std::string &_dest, const std::vector<std::string> &_options) { + format = _format; + source = _source; + dest = _dest; + options = _options; + location.initialize(&source); + scan_begin(); + yy::parser parse(*this); +// parse.set_debug_level(false); + int res = parse(); + scan_end(); + return res; +} + +void program::add_instruction(std::shared_ptr<instruction> inst) { + uint limit = MAX_INSTRUCTIONS; + if (instructions.size() >= limit) { + // todo take offset into account + std::stringstream msg; + msg << "program instruction limit of " << limit << " instruction(s) exceeded"; + throw syntax_error(inst->location, msg.str()); + } + if (!sideset_opt && !inst->sideset) { + std::stringstream msg; + msg << "instruction requires 'side' to specify side set value for the instruction because non optional sideset was specified for the program at " << sideset.location; + throw syntax_error(inst->location, msg.str()); + } + instructions.push_back(inst); +} + +using syntax_error = yy::parser::syntax_error; + +void program::add_symbol(std::shared_ptr<symbol> symbol) { + const auto &existing = pioasm->get_symbol(symbol->name, this); + if (existing) { + std::stringstream msg; + if (symbol->is_label != existing->is_label) { + msg << "'" << symbol->name << "' was already defined as a " << (existing->is_label ? "label" : "value") + << " at " << existing->location; + } else if (symbol->is_label) { + msg << "label '" << symbol->name << "' was already defined at " << existing->location; + } else { + msg << "'" << symbol->name << "' was already defined at " << existing->location; + } + throw syntax_error(symbol->location, msg.str()); + } + symbols.insert(std::pair<std::string, std::shared_ptr<::symbol>>(symbol->name, symbol)); + ordered_symbols.push_back(symbol); +} + +int resolvable::resolve(const program &program) { + return resolve(program.pioasm, &program); +} + +int unary_operation::resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) { + int value = arg->resolve(pioasm, program, scope); + switch (op) { + case negate: + return -value; + case reverse: { + // slow is fine + uint result = 0; + for (uint i = 0; i < 32; i++) { + result <<= 1u; + if (value & 1u) { + result |= 1u; + } + value >>= 1u; + } + return result; + } + default: + throw syntax_error(location, "internal error"); + } +} + +int binary_operation::resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) { + int lvalue = left->resolve(pioasm, program, scope); + int rvalue = right->resolve(pioasm, program, scope); + switch (op) { + case add: + return lvalue + rvalue; + case subtract: + return lvalue - rvalue; + case multiply: + return lvalue * rvalue; + case divide: + return lvalue / rvalue; + case and_: + return lvalue & rvalue; + case or_: + return lvalue | rvalue; + case xor_: + return lvalue ^ rvalue; + default: + throw syntax_error(location, "internal error"); + } +} + +void program::set_wrap(const yy::location &l) { + if (wrap) { + std::stringstream msg; + msg << ".wrap was already specified at " << wrap->location; + throw syntax_error(l, msg.str()); + } + if (instructions.empty()) { + throw syntax_error(l, ".wrap cannot be placed before the first program instruction"); + } + wrap = resolvable_int(l, instructions.size() - 1); +} + +void program::set_wrap_target(const yy::location &l) { + if (wrap_target) { + std::stringstream msg; + msg << ".wrap_target was already specified at " << wrap_target->location; + throw syntax_error(l, msg.str()); + } + wrap_target = resolvable_int(l, instructions.size()); +} + +void program::add_code_block(const code_block &block) { + code_blocks[block.lang].push_back(block); +} + +void program::add_lang_opt(std::string lang, std::string name, std::string value) { + lang_opts[lang].emplace_back(name, value); +} + +void program::finalize() { + if (sideset.value) { + int bits = sideset.value->resolve(*this); + if (bits < 0) { + throw syntax_error(sideset.value->location, "number of side set bits must be positive"); + } + sideset_max = (1u << bits) - 1; + if (sideset_opt) bits++; + sideset_bits_including_opt = bits; + if (bits > 5) { + if (sideset_opt) + throw syntax_error(sideset.value->location, "maximum number of side set bits with optional is 4"); + else + throw syntax_error(sideset.value->location, "maximum number of side set bits is 5"); + } + delay_max = (1u << (5 - bits)) - 1; + } else { + sideset_max = 0; + delay_max = 31; + } +} + +int name_ref::resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) { + auto symbol = pioasm->get_symbol(name, program); + if (symbol) { + if (symbol->resolve_started) { + std::stringstream msg; + msg << "circular dependency in definition of '" << name << "'; detected at " << location << ")"; + throw syntax_error(scope.location, msg.str()); + } + try { + symbol->resolve_started++; + int rc = symbol->value->resolve(pioasm, program, scope); + symbol->resolve_started--; + return rc; + } catch (syntax_error &e) { + symbol->resolve_started--; + throw e; + } + } else { + std::stringstream msg; + msg << "undefined symbol '" << name << "'"; + throw syntax_error(location, msg.str()); + } +} + +uint instruction::encode(const program &program) { + raw_encoding raw = raw_encode(program); + int _delay = delay->resolve(program); + if (_delay < 0) { + throw syntax_error(delay->location, "instruction delay must be positive"); + } + if (_delay > program.delay_max) { + if (program.delay_max == 31) { + throw syntax_error(delay->location, "instruction delay must be <= 31"); + } else { + std::stringstream msg; + msg << "the instruction delay limit is " << program.delay_max << " because of the side set specified at " + << program.sideset.location; + throw syntax_error(delay->location, msg.str()); + } + } + int _sideset = 0; + if (sideset) { + _sideset = sideset->resolve(program); + if (_sideset < 0) { + throw syntax_error(sideset->location, "side set value must be >=0"); + } + if (_sideset > program.sideset_max) { + std::stringstream msg; + msg << "the maximum side set value is " << program.sideset_max << " based on the configuration specified at " + << program.sideset.location; + throw syntax_error(sideset->location, msg.str()); + } + _sideset <<= (5u - program.sideset_bits_including_opt); + if (program.sideset_opt) { + _sideset |= 0x10u; + } + } + return (((uint) raw.type) << 13u) | (((uint) _delay | (uint) _sideset) << 8u) | (raw.arg1 << 5u) | raw.arg2; +} + +raw_encoding instruction::raw_encode(const program &program) { + throw syntax_error(location, "internal error"); +} + +uint instr_word::encode(const program &program) { + uint value = encoding->resolve(program); + if (value > 0xffffu) { + throw syntax_error(location, ".word value must be a positive 16 bit value"); + } + return value; +} + +raw_encoding instr_jmp::raw_encode(const program &program) { + int dest = target->resolve(program); + if (dest < 0) { + throw syntax_error(target->location, "jmp target address must be positive"); + } else if (dest >= (int)program.instructions.size()) { + std::stringstream msg; + msg << "jmp target address " << dest << " is beyond the end of the program"; + throw syntax_error(target->location, msg.str()); + } + return {inst_type::jmp, (uint) cond, (uint) dest}; +} + +raw_encoding instr_in::raw_encode(const program &program) { + int v = value->resolve(program); + if (v < 1 || v > 32) { + throw syntax_error(value->location, "'in' bit count must be >= 1 and <= 32"); + } + return {inst_type::in, (uint) src, (uint) v & 0x1fu}; +} + +raw_encoding instr_out::raw_encode(const program &program) { + int v = value->resolve(program); + if (v < 1 || v > 32) { + throw syntax_error(value->location, "'out' bit count must be >= 1 and <= 32"); + } + return {inst_type::out, (uint) dest, (uint) v & 0x1fu}; +} + +raw_encoding instr_set::raw_encode(const program &program) { + int v = value->resolve(program); + if (v < 0 || v > 31) { + throw syntax_error(value->location, "'set' bit count must be >= 0 and <= 31"); + } + return {inst_type::set, (uint) dest, (uint) v}; +} + +raw_encoding instr_wait::raw_encode(const program &program) { + uint pol = polarity->resolve(program); + if (pol > 1) { + throw syntax_error(polarity->location, "'wait' polarity must be 0 or 1"); + } + uint arg2 = source->param->resolve(program); + switch (source->target) { + case wait_source::irq: + if (arg2 > 7) throw syntax_error(source->param->location, "irq number must be must be >= 0 and <= 7"); + break; + case wait_source::gpio: + if (arg2 > 31) + throw syntax_error(source->param->location, "absolute GPIO number must be must be >= 0 and <= 31"); + break; + case wait_source::pin: + if (arg2 > 31) throw syntax_error(polarity->location, "pin number must be must be >= 0 and <= 31"); + break; + } + return {inst_type::wait, (pol << 2u) | (uint) source->target, arg2 | (source->flag ? 0x10u : 0u)}; +} + +raw_encoding instr_irq::raw_encode(const program &program) { + uint arg2 = num->resolve(program); + if (arg2 > 7) throw syntax_error(num->location, "irq number must be must be >= 0 and <= 7"); + if (relative) arg2 |= 0x10u; + return {inst_type::irq, (uint)modifiers, arg2}; +} + +std::vector<compiled_source::symbol> pio_assembler::public_symbols(program &program) { + std::vector<std::shared_ptr<symbol>> public_symbols; + std::remove_copy_if(program.ordered_symbols.begin(), program.ordered_symbols.end(), + std::inserter(public_symbols, public_symbols.end()), + [](const std::shared_ptr<symbol> &s) { return !s->is_public; }); + + std::vector<compiled_source::symbol> rc; + std::transform(public_symbols.begin(), public_symbols.end(), std::back_inserter(rc), + [&](const std::shared_ptr<symbol> &s) { + return compiled_source::symbol(s->name, s->value->resolve(program), s->is_label); + }); + return rc; +} + +int pio_assembler::write_output() { + std::set<std::string> known_output_formats; + std::transform(output_format::all().begin(), output_format::all().end(), + std::inserter(known_output_formats, known_output_formats.begin()), + [&](std::shared_ptr<output_format> &f) { + return f->name; + }); + + compiled_source source; + source.global_symbols = public_symbols(get_dummy_global_program()); + for (auto &program : programs) { + program.finalize(); + source.programs.emplace_back(compiled_source::program(program.name)); + auto &cprogram = source.programs[source.programs.size() - 1]; + cprogram = compiled_source::program(program.name); + + // encode the instructions + std::transform(program.instructions.begin(), program.instructions.end(), + std::back_inserter(cprogram.instructions), [&](std::shared_ptr<instruction> &inst) { + return inst->encode(program); + }); + + for (const auto &e : program.code_blocks) { + bool ok = false; + for(const auto &o : known_output_formats) { + if (o == e.first || 0 == e.first.find(o+"-")) { + ok = true; + break; + } + } + if (!ok) { + std::cerr << e.second[0].location << ": warning, unknown code block output type '" << e.first << "'\n"; + known_output_formats.insert(e.first); + } + } + + if (program.wrap) cprogram.wrap = program.wrap->resolve(program); else cprogram.wrap = std::max((int)program.instructions.size() - 1, 0); + if (program.wrap_target) cprogram.wrap_target = program.wrap_target->resolve(program); else cprogram.wrap_target = 0; + if (program.origin.value) cprogram.origin = program.origin.value->resolve(program); + if (program.sideset.value) { + cprogram.sideset_bits_including_opt = program.sideset_bits_including_opt; + cprogram.sideset_opt = program.sideset_opt; + cprogram.sideset_pindirs = program.sideset_pindirs; + } + std::transform(program.code_blocks.begin(), program.code_blocks.end(), std::inserter(cprogram.code_blocks, cprogram.code_blocks.begin()), [](const std::pair<std::string, std::vector<code_block>>&e) { + std::vector<std::string> blocks; + std::transform(e.second.begin(), e.second.end(), std::back_inserter(blocks), [&](const code_block& block) { + return block.contents; + }); + return std::pair<std::string, std::vector<std::string>>(e.first, blocks); + }); + cprogram.lang_opts = program.lang_opts; + cprogram.symbols = public_symbols(program); + } + if (programs.empty()) { + std::cout << "warning: input contained no programs" << std::endl; + } + return format->output(dest, options, source); +} + +FILE *output_format::open_single_output(std::string destination) { + FILE *out = destination == "-" ? stdout : fopen(destination.c_str(), "w"); + if (!out) { + std::cerr << "Can't open output file '" << destination << "'" << std::endl; + } + return out; +} diff --git a/circuitpython/ports/raspberrypi/sdk/tools/pioasm/pio_assembler.h b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/pio_assembler.h new file mode 100644 index 0000000..7183800 --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/pio_assembler.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _PIO_ASSEMBLER_H +#define _PIO_ASSEMBLER_H + +#include <algorithm> +#include "parser.hpp" +#include "output_format.h" + +// Give Flex the prototype of yylex we want ... +# define YY_DECL \ + yy::parser::symbol_type yylex (pio_assembler& pioasm) +// ... and declare it for the parser's sake. +YY_DECL; + + +struct pio_assembler { +public: + using syntax_error = yy::parser::syntax_error; + using location_type = yy::parser::location_type; + + std::shared_ptr<program> dummy_global_program; + std::vector<program> programs; + int error_count = 0; + + pio_assembler(); + + std::shared_ptr<output_format> format; + // The name of the file being parsed. + std::string source; + // name of the output file or "-" for stdout + std::string dest; + std::vector<std::string> options; + + int write_output(); + + bool add_program(const yy::location &l, const std::string &name) { + if (std::find_if(programs.begin(), programs.end(), [&](const program &p) { return p.name == name; }) == + programs.end()) { + programs.emplace_back(this, l, name); + return true; + } else { + return false; + } + } + + program &get_dummy_global_program() { + if (!dummy_global_program) { + dummy_global_program = std::shared_ptr<program>(new program(this, yy::location(&source), "")); + } + return *dummy_global_program; + } + + program &get_current_program(const location_type &l, const std::string &requiring_program, + bool before_any_instructions = false, bool disallow_global = true) { + if (programs.empty()) { + if (disallow_global) { + std::stringstream msg; + msg << requiring_program << " is invalid outside of a program"; + throw syntax_error(l, msg.str()); + } + return get_dummy_global_program(); + } + auto &p = programs[programs.size() - 1]; + if (before_any_instructions && !p.instructions.empty()) { + std::stringstream msg; + msg << requiring_program << " must preceed any program instructions"; + throw syntax_error(l, msg.str()); + } + return p; + } + + // note p may be null for global symbols only + std::shared_ptr<symbol> get_symbol(const std::string &name, const program *p) { + const auto &i = get_dummy_global_program().symbols.find(name); + if (i != get_dummy_global_program().symbols.end()) + return i->second; + + if (p) { + const auto &i2 = p->symbols.find(name); + if (i2 != p->symbols.end()) + return i2->second; + } + return nullptr; + } + + std::vector<compiled_source::symbol> public_symbols(program &program); + int generate(std::shared_ptr<output_format> _format, const std::string &_source, const std::string &_dest, + const std::vector<std::string> &_options = std::vector<std::string>()); + + // Handling the scanner. + void scan_begin(); + void scan_end(); + + // The token's location used by the scanner. + yy::location location; +}; + +#endif
\ No newline at end of file diff --git a/circuitpython/ports/raspberrypi/sdk/tools/pioasm/pio_disassembler.cpp b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/pio_disassembler.cpp new file mode 100644 index 0000000..c30fb0b --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/pio_disassembler.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <array> +#include <sstream> +#include <iomanip> +#include "pio_disassembler.h" + +extern "C" void disassemble(char *buf, int buf_len, uint16_t inst, uint sideset_bits, bool sideset_opt) { + if (buf_len) buf[disassemble(inst, sideset_bits, sideset_opt).copy(buf, buf_len - 1)] = 0; +} + +std::string disassemble(uint16_t inst, uint sideset_bits_including_opt, bool sideset_opt) { + std::stringstream ss; + uint major = inst >> 13u; + uint arg1 = ((uint) inst >> 5u) & 0x7u; + uint arg2 = inst & 0x1fu; + auto op = [&](const std::string &s) { + ss << std::left << std::setw(7) << s; + }; + auto op_guts = [&](const std::string &s) { + ss << std::left << std::setw(16) << s; + }; + + bool invalid = false; + switch (major) { + case 0b000: { + static std::array<std::string, 8> conditions{"", "!x, ", "x--, ", "!y, ", "y--, ", "x != y, ", "pin, ", + "!osre, "}; + op("jmp"); + op_guts(conditions[arg1] + std::to_string(arg2)); + break; + } + case 0b001: { + uint source = arg1 & 3u; + std::string guts; + switch (source) { + case 0b00: + guts = "gpio, " + std::to_string(arg2); + break; + case 0b01: + guts = "pin, " + std::to_string(arg2); + break; + case 0b10: + if (arg2 & 0x8u) { + invalid = true; + } else { + guts = "irq, " + std::to_string(arg2 & 7u); + if (arg2 & 0x10u) { + guts += " rel"; + } + } + break; + } + if (!invalid) { + guts = ((arg1 & 4u) ? "1 " : "0 ") + guts; + op("wait"); + op_guts(guts); + } + break; + } + case 0b010: { + static std::array<std::string, 8> sources { "pins", "x", "y", "null", "", "status", "isr", "osr"}; + std::string source = sources[arg1]; + if (source.empty()) { + invalid = true; + } else { + op("in"); + op_guts(source + ", " + std::to_string(arg2 ? arg2 : 32)); + } + break; + } + case 0b011: { + static std::array<std::string, 8> dests { "pins", "x", "y", "null", "pindirs", "pc", "isr", "exec"}; + op("out"); + op_guts(dests[arg1] + ", " + std::to_string(arg2 ? arg2 : 32)); + break; + } + case 0b100: { + if (arg2) { + invalid = true; + } else { + std::string guts = ""; + if (arg1 & 4u) { + op("pull"); + if (arg1 & 2u) guts = "ifempty "; + } else { + op("push"); + if (arg1 & 2u) guts = "iffull "; + } + guts += (arg1 & 0x1u) ? "block" : "noblock"; + op_guts(guts); + } + break; + } + case 0b101: { + static std::array<std::string, 8> dests { "pins", "x", "y", "", "exec", "pc", "isr", "osr"}; + static std::array<std::string, 8> sources { "pins", "x", "y", "null", "", "status", "isr", "osr"}; + std::string dest = dests[arg1]; + std::string source = sources[arg2 & 7u]; + uint operation = arg2 >> 3u; + if (source.empty() || dest.empty() || operation == 3) { + invalid = true; + } + if (dest == source && !operation && (arg1 == 1 || arg2 == 2)) { + op("nop"); + op_guts(""); + } else { + op("mov"); + std::string guts = dest + ", "; + if (operation == 1) { + guts += "!"; + } else if (operation == 2) { + guts += "::"; + } + guts += source; + op_guts(guts); + } + break; + } + case 0b110: { + if ((arg1 & 0x4u) || (arg2 & 0x8u)) { + invalid = true; + } else { + op("irq"); + std::string guts; + if (arg1 & 0x2u) { + guts += "clear "; + } else if (arg1 & 0x1u) { + guts += "wait "; + } else { + guts += "nowait "; + } + guts += std::to_string(arg2 & 7u); + if (arg2 & 0x10u) { + guts += " rel"; + } + op_guts(guts); + } + break; + } + case 0b111: { + static std::array<std::string, 8> dests{"pins", "x", "y", "", "pindirs", "", "", ""}; + std::string dest = dests[arg1]; + if (dest.empty()) { + invalid = true; + } else { + op("set"); + op_guts(dests[arg1] + ", " + std::to_string(arg2)); + } + break; + } + } + if (invalid) { + return "reserved"; + } + uint delay = ((uint) inst >> 8u) & 0x1f; + ss << std::left << std::setw(7); + if (sideset_bits_including_opt && (!sideset_opt || (delay & 0x10u))) { + ss << ("side "+ std::to_string((delay & (sideset_opt ? 0xfu : 0x1fu)) >> (5u - sideset_bits_including_opt))); + } else { + ss << ""; + } + delay &= ((1u << (5 - sideset_bits_including_opt)) - 1u); + ss << std::left << std::setw(4) << (delay ? ("[" + std::to_string(delay) + "]") : ""); + return ss.str(); +} + diff --git a/circuitpython/ports/raspberrypi/sdk/tools/pioasm/pio_disassembler.h b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/pio_disassembler.h new file mode 100644 index 0000000..669e08d --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/pio_disassembler.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _PIO_DISASSEMBLER_H +#define _PIO_DISASSEMBLER_H + +#ifdef __cplusplus + +#include <string> + +typedef unsigned int uint; + +std::string disassemble(uint16_t inst, uint sideset_bits, bool sideset_opt); +extern "C" void disassemble(char *buf, int buf_len, uint16_t inst, uint sideset_bits, bool sideset_opt); +#else +void disassemble(char *buf, int buf_len, uint inst, uint sideset_bits, bool sideset_opt); +#endif + +#endif
\ No newline at end of file diff --git a/circuitpython/ports/raspberrypi/sdk/tools/pioasm/pio_types.h b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/pio_types.h new file mode 100644 index 0000000..d262849 --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/pio_types.h @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _PIO_TYPES_H +#define _PIO_TYPES_H + +#include <string> +#include <map> +#include <set> +#include <utility> +#include <vector> +#include <memory> + +#include "location.h" + +typedef unsigned int uint; + +enum struct inst_type { + jmp = 0x0, + wait = 0x1, + in = 0x2, + out = 0x3, + push_pull = 0x4, + mov = 0x5, + irq = 0x6, + set = 0x7, +}; + +/* condition codes */ +enum struct condition { + al = 0x0, + xz = 0x1, + xnz__ = 0x2, + yz = 0x3, + ynz__ = 0x4, + xney = 0x5, + pin = 0x6, + osrez = 0x7, +}; + +/* in source / out / set target - not all valid */ +enum struct in_out_set { + in_out_set_pins = 0x0, + in_out_set_x = 0x1, + in_out_set_y = 0x2, + in_out_null = 0x3, + in_out_set_pindirs = 0x4, + in_status = 0x5, + out_set_pc = 0x5, + in_out_isr = 0x6, + in_osr = 0x7, + out_exec = 0x7, +}; + +enum struct irq { + set = 0x0, + set_wait = 0x1, + clear = 0x2, +}; + +// mov src/dest (not all valid) +enum struct mov { + pins = 0x0, + x = 0x1, + y = 0x2, + null = 0x3, + exec = 0x4, + pc = 0x5, + status = 0x5, + isr = 0x6, + osr = 0x7, +}; + +enum struct mov_op { + none = 0x0, + invert = 0x1, + bit_reverse = 0x2, +}; + +struct src_item { + yy::location location; + + src_item() = default; + + explicit src_item(const yy::location &location) : location(location) {} +}; + +struct program; +struct pio_assembler; + +struct resolvable : public src_item { + resolvable(const yy::location &l) : src_item(l) {} + + int resolve(const program &program); + + int resolve(pio_assembler *pioasm, const program *program) { + return resolve(pioasm, program, *this); + } + + virtual int resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) = 0; +}; + +using rvalue = std::shared_ptr<resolvable>; + +struct wait_source { + enum type { + gpio = 0x0, + pin = 0x1, + irq = 0x2 + } target; + rvalue param; + bool flag; + + wait_source(type target, rvalue param, bool flag = false) : target(target), param(std::move(param)), flag(flag) {} +}; + +struct name_ref : public resolvable { + std::string name; + + name_ref(const yy::location &l, std::string name) : resolvable(l), name(std::move(name)) {} + + int resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) override; +}; + +struct code_block : public resolvable { + std::string lang; + std::string contents; + + code_block(const yy::location &l, std::string lang, std::string contents) : resolvable(l), lang(std::move(lang)), + contents(std::move(contents)) {} + + int resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) override { + return 0; + } +}; + +struct int_value : public resolvable { + int value; + + int_value(const yy::location &l, int value) : resolvable(l), value(value) {} + + int resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) override { + return value; + } +}; + +static inline rvalue resolvable_int(const yy::location &l, int v) { + return std::shared_ptr<resolvable>(new int_value(l, v)); +} + +struct binary_operation : public resolvable { + enum op_type { + add, + subtract, + multiply, + divide, + and_, // pesky C++ + or_, + xor_ + }; + + op_type op; + rvalue left, right; + + binary_operation(const yy::location &l, op_type op, rvalue left, rvalue right) : + resolvable(l), op(op), left(std::move(left)), right(std::move(right)) {} + + int resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) override; +}; + +struct unary_operation : public resolvable { + enum op_type { + negate, + reverse + }; + + op_type op; + rvalue arg; + + unary_operation(const yy::location &l, op_type op, const rvalue &arg) : + resolvable(l), op(op), arg(arg) {} + + int resolve(pio_assembler *pioasm, const program *program, const resolvable &scope) override; +}; + +struct symbol : public src_item { + std::string name; + rvalue value; + bool is_public; + bool is_label; + int resolve_started; + + symbol(const yy::location &l, std::string name, bool is_extern = false) : src_item(l), name(std::move(name)), + is_public(is_extern), is_label(false), + resolve_started(false) {} +}; + +struct raw_encoding { + enum inst_type type; + uint arg1; + uint arg2; +}; + +struct instruction : public src_item { + rvalue sideset; // possibly null + rvalue delay; + + instruction(const yy::location &l) : src_item(l) {} + + virtual uint encode(const program &program); + + virtual raw_encoding raw_encode(const program &program); +}; + +struct pio_assembler; + +// rvalue with extra encompassing location +struct rvalue_loc { + rvalue value; + yy::location location; + + rvalue_loc() = default; + + rvalue_loc(const rvalue &v, const yy::location &l) : value(v), location(l) {} +}; + +struct program : public src_item { + static const int MAX_INSTRUCTIONS = 32; + + pio_assembler *pioasm; + std::string name; + rvalue_loc origin; + rvalue_loc sideset; + bool sideset_opt; + bool sideset_pindirs; + + rvalue wrap_target; + rvalue wrap; + + std::map<std::string, std::shared_ptr<symbol>> symbols; + std::vector<std::shared_ptr<symbol>> ordered_symbols; + std::vector<std::shared_ptr<instruction>> instructions; + std::map<std::string, std::vector<code_block>> code_blocks; + std::map<std::string, std::vector<std::pair<std::string,std::string>>> lang_opts; + + // post finalization + int delay_max; + int sideset_bits_including_opt; // specified side set bits + 1 if we need presence flag + int sideset_max; + + program(pio_assembler *pioasm, const yy::location &l, std::string name) : + src_item(l), pioasm(pioasm), name(std::move(name)), sideset_opt(true), sideset_pindirs(false) {} + + void set_origin(const yy::location &l, const rvalue &_origin) { + origin = rvalue_loc(_origin, l); + } + + void set_wrap_target(const yy::location &l); + + void set_wrap(const yy::location &l); + + void set_sideset(const yy::location &l, rvalue _sideset, bool optional, bool pindirs) { + sideset = rvalue_loc(_sideset, l); + sideset_opt = optional; + sideset_pindirs = pindirs; + } + + void add_label(std::shared_ptr<symbol> label) { + label->value = resolvable_int(label->location, instructions.size()); + add_symbol(label); + } + + void add_symbol(std::shared_ptr<symbol> symbol); + + void add_instruction(std::shared_ptr<instruction> inst); + + void add_code_block(const code_block &block); + + void add_lang_opt(std::string lang, std::string name, std::string value); + void finalize(); +}; + +struct instr_jmp : public instruction { + condition cond; + rvalue target; + + instr_jmp(const yy::location &l, condition c, rvalue target) : instruction(l), cond(c), target(std::move(target)) { } + + raw_encoding raw_encode(const program &program) override; +}; + +struct instr_wait : public instruction { + rvalue polarity; + std::shared_ptr<wait_source> source; + + instr_wait(const yy::location &l, rvalue polarity, std::shared_ptr<wait_source> source) : instruction(l), polarity( + std::move(polarity)), source(std::move(source)) {} + + raw_encoding raw_encode(const program &program) override; +}; + +struct instr_in : public instruction { + enum in_out_set src; + rvalue value; + + instr_in(const yy::location &l, const enum in_out_set &src, rvalue value) : instruction(l), src(src), + value(std::move(value)) {} + + raw_encoding raw_encode(const program &program) override; +}; + +struct instr_out : public instruction { + enum in_out_set dest; + rvalue value; + + instr_out(const yy::location &l, const enum in_out_set &dest, rvalue value) : instruction(l), dest(dest), + value(std::move(value)) {} + + raw_encoding raw_encode(const program &program) override; +}; + +struct instr_set : public instruction { + enum in_out_set dest; + rvalue value; + + instr_set(const yy::location &l, const enum in_out_set &dest, rvalue value) : instruction(l), dest(dest), + value(std::move(value)) {} + + raw_encoding raw_encode(const program &program) override; +}; + + +struct instr_push : public instruction { + bool if_full, blocking; + + instr_push(const yy::location &l, bool if_full, bool blocking) : instruction(l), if_full(if_full), + blocking(blocking) {} + + raw_encoding raw_encode(const program &program) override { + uint arg1 = (blocking ? 1u : 0u) | (if_full ? 0x2u : 0); + return {inst_type::push_pull, arg1, 0}; + } +}; + +struct instr_pull : public instruction { + bool if_empty, blocking; + + instr_pull(const yy::location &l, bool if_empty, bool blocking) : instruction(l), if_empty(if_empty), + blocking(blocking) {} + + raw_encoding raw_encode(const program &program) override { + uint arg1 = (blocking ? 1u : 0u) | (if_empty ? 0x2u : 0) | 0x4u; + return {inst_type::push_pull, arg1, 0}; + } +}; + +struct instr_mov : public instruction { + enum mov dest, src; + mov_op op; + + instr_mov(const yy::location &l, const enum mov &dest, const enum mov &src, const mov_op& op = mov_op::none) : + instruction(l), dest(dest), src(src), op(op) {} + + raw_encoding raw_encode(const program &program) override { + return {inst_type::mov, (uint) dest, (uint)src | ((uint)op << 3u)}; + } +}; + +struct instr_irq : public instruction { + enum irq modifiers; + rvalue num; + bool relative; + + instr_irq(const yy::location &l, const enum irq &modifiers, rvalue num, bool relative = false) : + instruction(l), modifiers(modifiers), num(std::move(num)), relative(relative) {} + + raw_encoding raw_encode(const program &program) override; +}; + + +struct instr_nop : public instr_mov { + instr_nop(const yy::location &l) : instr_mov(l, mov::y, mov::y) {} +}; + +struct instr_word : public instruction { + rvalue encoding; + + instr_word(const yy::location &l, rvalue encoding) : instruction(l), encoding(std::move(encoding)) {} + + uint encode(const program &program) override; +}; + +#endif
\ No newline at end of file diff --git a/circuitpython/ports/raspberrypi/sdk/tools/pioasm/python_output.cpp b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/python_output.cpp new file mode 100644 index 0000000..38f7ffe --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/python_output.cpp @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <array> +#include <algorithm> +#include <sstream> +#include <iomanip> +#include <iostream> +#include "output_format.h" +#include "pio_disassembler.h" + +struct python_output : public output_format { + struct factory { + factory() { + output_format::add(new python_output()); + } + }; + + python_output() : output_format("python") {} + + std::string get_description() override { + return "Python file suitable for use with MicroPython"; + } + + void output_symbols(FILE *out, std::string prefix, const std::vector<compiled_source::symbol> &symbols) { + int count = 0; + for (const auto &s : symbols) { + if (!s.is_label) { + fprintf(out, "%s%s = %d\n", prefix.c_str(), s.name.c_str(), s.value); + count++; + } + } + if (count) { + fprintf(out, "\n"); + count = 0; + } + for (const auto &s : symbols) { + if (s.is_label) { + fprintf(out, "%soffset_%s = %d\n", prefix.c_str(), s.name.c_str(), s.value); + count++; + } + } + if (count) { + fprintf(out, "\n"); + } + } + + void header(FILE *out, std::string msg) { + std::string dashes = std::string(msg.length(), '-'); + fprintf(out, "# %s #\n", dashes.c_str()); + fprintf(out, "# %s #\n", msg.c_str()); + fprintf(out, "# %s #\n", dashes.c_str()); + fprintf(out, "\n"); + } + + int output(std::string destination, std::vector<std::string> output_options, + const compiled_source &source) override { + FILE *out = open_single_output(destination); + if (!out) return 1; + + header(out, "This file is autogenerated by pioasm; do not edit!"); + + fprintf(out, "import rp2\n"); + fprintf(out, "from machine import Pin"); + fprintf(out, "\n"); + + output_symbols(out, "", source.global_symbols); + + for (const auto &program : source.programs) { + header(out, program.name); + + std::string prefix = program.name + "_"; + + output_symbols(out, prefix, program.symbols); + + int param_count = 0; + auto write_opt = [&] (std::string name, std::string value) { + if (param_count++) { + fprintf(out, ", "); + } + fprintf(out, "%s=%s", name.c_str(), value.c_str()); + }; + fprintf(out, "@rp2.asm_pio("); + for(const auto &p : program.lang_opts) { + if (p.first.size() >= name.size() && p.first.compare(0, name.size(), name) == 0) { + for (const auto &p2 : p.second) { + write_opt(p2.first, p2.second); + } + } + } + fprintf(out, ")\n"); + fprintf(out, "def %s():\n", program.name.c_str()); + + std::map<uint, std::string> jmp_labels; + // for now just use numeric labels + for (int i = 0; i < (int)program.instructions.size(); i++) { + const auto &inst = program.instructions[i]; + if (!(inst >> 13u)) { + // a jump + uint target = inst &0x1fu; + jmp_labels.insert(std::pair<uint,std::string>(target, std::to_string(target))); + } + } + + for (uint i = 0; i < (int)program.instructions.size(); i++) { + const auto &inst = program.instructions[i]; + if (i == program.wrap_target) { + fprintf(out, " wrap_target()\n"); + } + auto it = jmp_labels.find(i); + if (it != jmp_labels.end()) { + fprintf(out, " label(\"%s\")\n", it->second.c_str()); + } + fprintf(out, " %s # %d\n", disassemble(jmp_labels, inst, program.sideset_bits_including_opt.get(), program.sideset_opt).c_str(), i); + if (i == program.wrap) { + fprintf(out, " wrap()\n"); + } + } + fprintf(out, "\n"); + + /* + fprintf(out, "static inline pio_sm_config %sprogram_default_config(uint offset) {\n", prefix.c_str()); + fprintf(out, " pio_sm_config c = pio_sm_default_config();\n"); + fprintf(out, " sm_config_wrap(&c, offset + %swrap_target, offset + %swrap);\n", prefix.c_str(), + prefix.c_str()); + if (program.sideset_bits_including_opt.is_specified()) { + fprintf(out, " sm_config_sideset(&c, %d, %s, %s);\n", program.sideset_bits_including_opt.get(), + program.sideset_opt ? "true" : "false", + program.sideset_pindirs ? "true" : "false"); + } + fprintf(out, " return c;\n"); + fprintf(out, "}\n"); +*/ + // todo maybe have some code blocks inside or outside here? + for(const auto& o : program.code_blocks) { + fprintf(out, "\n"); + if (o.first == name) { + for(const auto &contents : o.second) { + fprintf(out, "%s", contents.c_str()); + fprintf(out, "\n"); + } + } + } + + fprintf(out, "\n"); + } + if (out != stdout) { fclose(out); } + return 0; + } + + static std::string disassemble(const std::map<uint, std::string>& jmp_labels, uint16_t inst, uint sideset_bits_including_opt, bool sideset_opt) { + std::stringstream ss; + uint major = inst >> 13u; + uint arg1 = ((uint) inst >> 5u) & 0x7u; + uint arg2 = inst & 0x1fu; + std::string op_string; + auto op = [&](const std::string &s) { + op_string = s; + }; + auto op_guts = [&](const std::string &s) { + ss << std::left << std::setw(24) << (op_string + "(" + s + ")"); + }; + + bool invalid = false; + switch (major) { + case 0b000: { + static std::array<std::string, 8> conditions{"", "not_x", "x_dec", "not_y", "y_dec", "x_not_y", "pin", + "not_osre"}; + op("jmp"); + auto it = jmp_labels.find(arg2); + std::string label = "?"; + if (it != jmp_labels.end()) { + label = it->second; + } + if (arg1) + op_guts(conditions[arg1] + ", \"" + label +"\""); + else + op_guts("\"" + label + "\""); + break; + } + case 0b001: { + uint source = arg1 & 3u; + std::string guts; + switch (source) { + case 0b00: + guts = "gpio, " + std::to_string(arg2); + break; + case 0b01: + guts = "pin, " + std::to_string(arg2); + break; + case 0b10: + if (arg2 & 0x8u) { + invalid = true; + } else { + guts = "irq, "; + auto irq = std::to_string(arg2 & 7u); + if (arg2 & 0x10u) { + guts += "rel(" + irq + ")"; + } else { + guts += irq; + } + } + break; + } + if (!invalid) { + guts = ((arg1 & 4u) ? "1, " : "0, ") + guts; + op("wait"); + op_guts(guts); + } + break; + } + case 0b010: { + static std::array<std::string, 8> sources { "pins", "x", "y", "null", "", "status", "isr", "osr"}; + std::string source = sources[arg1]; + if (source.empty()) { + invalid = true; + } else { + op("in_"); + op_guts(source + ", " + std::to_string(arg2 ? arg2 : 32)); + } + break; + } + case 0b011: { + static std::array<std::string, 8> dests { "pins", "x", "y", "null", "pindirs", "pc", "isr", "exec"}; + op("out"); + op_guts(dests[arg1] + ", " + std::to_string(arg2 ? arg2 : 32)); + break; + } + case 0b100: { + if (arg2) { + invalid = true; + } else { + std::string guts = ""; + if (arg1 & 4u) { + op("pull"); + if (arg1 & 2u) guts = "ifempty, "; + } else { + op("push"); + if (arg1 & 2u) guts = "iffull, "; + } + guts += ((arg1 & 0x1u) ? "block" : "noblock"); + op_guts(guts); + } + break; + } + case 0b101: { + static std::array<std::string, 8> dests { "pins", "x", "y", "", "exec", "pc", "isr", "osr"}; + static std::array<std::string, 8> sources { "pins", "x", "y", "null", "", "status", "isr", "osr"}; + std::string dest = dests[arg1]; + std::string source = sources[arg2 & 7u]; + uint operation = arg2 >> 3u; + if (source.empty() || dest.empty() || operation == 3) { + invalid = true; + } + if (dest == source && (arg1 == 1 || arg2 == 2)) { + op("nop"); + op_guts(""); + } else { + op("mov"); + std::string guts = dest + ", "; + if (operation == 1) { + guts += "invert("; + } else if (operation == 2) { + guts += "reverse("; + } + guts += source; + if (operation == 1 || operation == 2) { + guts += ")"; + } + op_guts(guts); + } + break; + } + case 0b110: { + if ((arg1 & 0x4u) || (arg2 & 0x8u)) { + invalid = true; + } else { + op("irq"); + std::string guts; + if (arg1 & 0x2u) { + guts += "clear, "; + } else if (arg1 & 0x1u) { + guts += "wait, "; + } else { + guts += "nowait, "; + } + auto irq = std::to_string(arg2 & 7u); + if (arg2 & 0x10u) { + guts += "rel(" + irq + ")"; + } else { + guts += irq; + } + op_guts(guts); + } + break; + } + case 0b111: { + static std::array<std::string, 8> dests{"pins", "x", "y", "", "pindirs", "", "", ""}; + std::string dest = dests[arg1]; + if (dest.empty()) { + invalid = true; + } else { + op("set"); + op_guts(dests[arg1] + ", " + std::to_string(arg2)); + } + break; + } + } + if (invalid) { + op("word"); + ss << std::hex; + op_guts(std::to_string(inst)); + } + uint delay = ((uint) inst >> 8u) & 0x1f; + ss << std::left << std::setw(9); + if (sideset_bits_including_opt && (!sideset_opt || (delay & 0x10u))) { + ss << (".side("+ std::to_string((delay & (sideset_opt ? 0xfu : 0x1fu)) >> (5u - sideset_bits_including_opt))+")"); + } else { + ss << ""; + } + delay &= ((1u << (5 - sideset_bits_including_opt)) - 1u); + ss << std::left << std::setw(4) << (delay ? ("[" + std::to_string(delay) + "]") : ""); + return ss.str(); + } +}; + +static python_output::factory creator; |