pico-sdk/tools/pioasm/lexer.ll
graham sanderson 26653ea81e Initial Release
2021-01-20 10:44:27 -06:00

237 lines
10 KiB
LLVM
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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);
}