| /* |
| * 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\r] |
| 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(); } |
| "%}"{blank}* { 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); |
| } |