Squashed 'third_party/pico-sdk/' content from commit 2062372d2
Change-Id: Ic20f199d3ed0ea8d3a6a1bbf513f875ec7500cc6
git-subtree-dir: third_party/pico-sdk
git-subtree-split: 2062372d203b372849d573f252cf7c6dc2800c0a
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
new file mode 100644
index 0000000..f66f9d0
--- /dev/null
+++ b/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/tools/FindELF2UF2.cmake b/tools/FindELF2UF2.cmake
new file mode 100644
index 0000000..fb5dd97
--- /dev/null
+++ b/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/tools/FindPioasm.cmake b/tools/FindPioasm.cmake
new file mode 100644
index 0000000..91b9021
--- /dev/null
+++ b/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/tools/check_doxygen_groups.py b/tools/check_doxygen_groups.py
new file mode 100755
index 0000000..bbcd9f5
--- /dev/null
+++ b/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/tools/elf2uf2/CMakeLists.txt b/tools/elf2uf2/CMakeLists.txt
new file mode 100644
index 0000000..070e114
--- /dev/null
+++ b/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/tools/elf2uf2/elf.h b/tools/elf2uf2/elf.h
new file mode 100644
index 0000000..32e3dbb
--- /dev/null
+++ b/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/tools/elf2uf2/main.cpp b/tools/elf2uf2/main.cpp
new file mode 100644
index 0000000..2c0ddcd
--- /dev/null
+++ b/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/tools/extract_configs.py b/tools/extract_configs.py
new file mode 100755
index 0000000..e45ae7c
--- /dev/null
+++ b/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/tools/pioasm/CMakeLists.txt b/tools/pioasm/CMakeLists.txt
new file mode 100644
index 0000000..df80530
--- /dev/null
+++ b/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/tools/pioasm/ada_output.cpp b/tools/pioasm/ada_output.cpp
new file mode 100644
index 0000000..8598f33
--- /dev/null
+++ b/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/tools/pioasm/c_sdk_output.cpp b/tools/pioasm/c_sdk_output.cpp
new file mode 100644
index 0000000..9388c0d
--- /dev/null
+++ b/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/tools/pioasm/gen/lexer.cpp b/tools/pioasm/gen/lexer.cpp
new file mode 100644
index 0000000..5de6626
--- /dev/null
+++ b/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/tools/pioasm/gen/location.h b/tools/pioasm/gen/location.h
new file mode 100644
index 0000000..4965682
--- /dev/null
+++ b/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/tools/pioasm/gen/parser.cpp b/tools/pioasm/gen/parser.cpp
new file mode 100644
index 0000000..c9bd036
--- /dev/null
+++ b/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/tools/pioasm/gen/parser.hpp b/tools/pioasm/gen/parser.hpp
new file mode 100644
index 0000000..11d8393
--- /dev/null
+++ b/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/tools/pioasm/hex_output.cpp b/tools/pioasm/hex_output.cpp
new file mode 100644
index 0000000..39dd0fa
--- /dev/null
+++ b/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/tools/pioasm/lexer.ll b/tools/pioasm/lexer.ll
new file mode 100644
index 0000000..939b06f
--- /dev/null
+++ b/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/tools/pioasm/main.cpp b/tools/pioasm/main.cpp
new file mode 100644
index 0000000..e7ff686
--- /dev/null
+++ b/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/tools/pioasm/output_format.h b/tools/pioasm/output_format.h
new file mode 100644
index 0000000..2ba899d
--- /dev/null
+++ b/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/tools/pioasm/parser.yy b/tools/pioasm/parser.yy
new file mode 100644
index 0000000..467ca89
--- /dev/null
+++ b/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/tools/pioasm/pio_assembler.cpp b/tools/pioasm/pio_assembler.cpp
new file mode 100644
index 0000000..469d733
--- /dev/null
+++ b/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/tools/pioasm/pio_assembler.h b/tools/pioasm/pio_assembler.h
new file mode 100644
index 0000000..7183800
--- /dev/null
+++ b/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/tools/pioasm/pio_disassembler.cpp b/tools/pioasm/pio_disassembler.cpp
new file mode 100644
index 0000000..c30fb0b
--- /dev/null
+++ b/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/tools/pioasm/pio_disassembler.h b/tools/pioasm/pio_disassembler.h
new file mode 100644
index 0000000..669e08d
--- /dev/null
+++ b/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/tools/pioasm/pio_types.h b/tools/pioasm/pio_types.h
new file mode 100644
index 0000000..d262849
--- /dev/null
+++ b/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/tools/pioasm/python_output.cpp b/tools/pioasm/python_output.cpp
new file mode 100644
index 0000000..38f7ffe
--- /dev/null
+++ b/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;