Skip to content

Instantly share code, notes, and snippets.

@RavuAlHemio
Created April 1, 2012 14:32
Show Gist options
  • Save RavuAlHemio/2275628 to your computer and use it in GitHub Desktop.
Save RavuAlHemio/2275628 to your computer and use it in GitHub Desktop.
scanner/parser, Ox edition
/* vim: set ft=yacc: */
/*
@i isn't very implicit if I have to plaster
all of my code with it...
*/
%start ProgramOrEmpty
%token TOK_SYM_SEMI
%token TOK_SYM_PARBEG
%token TOK_SYM_PAREND
%token TOK_SYM_COMMA
%token TOK_SYM_EQUALS
%token TOK_SYM_TILDE
%token TOK_SYM_ARROW
%token TOK_SYM_MINUS
%token TOK_SYM_PLUS
%token TOK_SYM_ASTER
%token TOK_SYM_DOT
%token TOK_SYM_GT
%token TOK_SYM_USCORE
%token TOK_KEY_COND
%token TOK_KEY_END
%token TOK_KEY_NOT
%token TOK_KEY_OR
%token TOK_NUMBER
%token TOK_IDENT
%union {
unsigned int ival;
char *sval;
}
%{
#include "common.h"
#include "astmake.h"
extern ast_generic_node *ast_root;
%}
@attributes { ast_generic_node *n; } Program Funcdef Expr Term MinusNotSeries PlusSeries AsterSeries OrSeries DotSeries CondContentExpr Lexpr Lterm
@attributes { char *name; } TOK_IDENT
@attributes { numeric_type val; } TOK_NUMBER
@attributes { size_t argcount; char **argnames; } ParamNames
@attributes { size_t argcount; ast_generic_node **argexprs; } Params
@attributes { size_t casecount; ast_generic_node **cases; } CondExprSeries;
%%
ProgramOrEmpty
: Program
|
;
Program
: Program Funcdef TOK_SYM_SEMI
@{
@i ast_root = @Program.0.n@ = ast_make_program_expand(
@Program.1.n@,
@Funcdef.n@
);
@}
| Funcdef TOK_SYM_SEMI
@{
@i ast_root = @Program.n@ = ast_make_program(@Funcdef.n@);
@}
;
Funcdef
: TOK_IDENT /* Funktionsname */
TOK_SYM_PARBEG ParamNames TOK_SYM_PAREND /* Parameter */
TOK_SYM_EQUALS Expr /* Definition */
@{
@i @Funcdef.n@ = ast_make_funcdef(
@TOK_IDENT.name@,
@ParamNames.argcount@,
@ParamNames.argnames@,
@Expr.n@
);
free(@TOK_IDENT.name@);
@}
| TOK_IDENT
TOK_SYM_PARBEG TOK_SYM_PAREND /* parameterlos */
TOK_SYM_EQUALS Expr
@{
@i @Funcdef.n@ = ast_make_funcdef(
@TOK_IDENT.name@,
0, NULL,
@Expr.n@
);
free(@TOK_IDENT.name@);
@}
;
ParamNames
: ParamNames TOK_SYM_COMMA TOK_IDENT
@{
@i @ParamNames.0.argcount@ = @ParamNames.1.argcount@ + 1;
@i @ParamNames.0.argnames@ = ast_make_argnames_expand(
@ParamNames.1.argcount@,
@ParamNames.1.argnames@,
@TOK_IDENT.name@
);
free(@TOK_IDENT.name@);
@}
| TOK_IDENT
@{
@i @ParamNames.argcount@ = 1;
@i @ParamNames.argnames@ = ast_make_argnames(@TOK_IDENT.name@);
free(@TOK_IDENT.name@);
@}
;
Expr
: TOK_KEY_COND CondExprSeries TOK_SYM_ARROW Expr TOK_KEY_END
@{
@i @Expr.0.n@ = ast_make_cond(
@CondExprSeries.casecount@,
@CondExprSeries.cases@,
@Expr.1.n@
);
@}
| TOK_KEY_COND TOK_SYM_ARROW Expr TOK_KEY_END
@{
/*
Don't bother making a conditional construction here.
Just pass the expression upwards.
*/
@i @Expr.0.n@ = @Expr.1.n@;
@}
| Term
@{
@i @Expr.n@ = @Term.n@;
@}
| MinusNotSeries
@{
@i @Expr.n@ = @MinusNotSeries.n@;
@}
| PlusSeries
@{
@i @Expr.n@ = @PlusSeries.n@;
@}
| AsterSeries
@{
@i @Expr.n@ = @AsterSeries.n@;
@}
| OrSeries
@{
@i @Expr.n@ = @OrSeries.n@;
@}
| DotSeries
@{
@i @Expr.n@ = @DotSeries.n@;
@}
| Term TOK_SYM_GT Term
@{
@i @Expr.n@ = ast_make_binop(AST_OP_GT, @Term.0.n@, @Term.1.n@);
@}
| Term TOK_SYM_EQUALS Term
@{
@i @Expr.n@ = ast_make_binop(AST_OP_EQUAL, @Term.0.n@, @Term.1.n@);
@}
;
Term
: TOK_SYM_PARBEG Expr TOK_SYM_PAREND
@{
@i @Term.n@ = @Expr.n@;
@}
| TOK_NUMBER
@{
@i @Term.n@ = ast_make_number(@TOK_NUMBER.val@);
@}
| TOK_IDENT TOK_SYM_PARBEG TOK_SYM_PAREND
@{
@i @Term.n@ = ast_make_funccall(
@TOK_IDENT.name@,
0, NULL
);
free(@TOK_IDENT.name@);
@}
| TOK_IDENT TOK_SYM_PARBEG Params TOK_SYM_PAREND
@{
@i @Term.n@ = ast_make_funccall(
@TOK_IDENT.name@,
@Params.argcount@, @Params.argexprs@
);
free(@TOK_IDENT.name@);
@}
| TOK_IDENT
@{
@i @Term.n@ = ast_make_varacc(@TOK_IDENT.name@);
free(@TOK_IDENT.name@);
@}
;
Params
: Params TOK_SYM_COMMA Expr
@{
@i @Params.0.argcount@ = @Params.1.argcount@ + 1;
@i @Params.0.argexprs@ = ast_make_argexprs_expand(
@Params.1.argcount@,
@Params.1.argexprs@,
@Expr.n@
);
@}
| Expr
@{
@i @Params.argcount@ = 1;
@i @Params.argexprs@ = ast_make_argexprs(@Expr.n@);
@}
;
MinusNotSeries
: TOK_SYM_MINUS MinusNotSeries
@{
@i @MinusNotSeries.0.n@ = ast_make_unop(
AST_OP_MINUS, @MinusNotSeries.1.n@
);
@}
| TOK_KEY_NOT MinusNotSeries
@{
@i @MinusNotSeries.0.n@ = ast_make_unop(
AST_OP_NOT, @MinusNotSeries.1.n@
);
@}
| TOK_SYM_MINUS Term
@{
@i @MinusNotSeries.n@ = ast_make_unop(
AST_OP_MINUS, @Term.n@
);
@}
| TOK_KEY_NOT Term
@{
@i @MinusNotSeries.n@ = ast_make_unop(
AST_OP_NOT, @Term.n@
);
@}
;
PlusSeries
: PlusSeries TOK_SYM_PLUS Term
@{
@i @PlusSeries.0.n@ = ast_make_binop(
AST_OP_ADD,
@PlusSeries.1.n@,
@Term.n@
);
@}
| Term TOK_SYM_PLUS Term
@{
@i @PlusSeries.n@ = ast_make_binop(
AST_OP_ADD,
@Term.0.n@,
@Term.1.n@
);
@}
;
AsterSeries
: AsterSeries TOK_SYM_ASTER Term
@{
@i @AsterSeries.0.n@ = ast_make_binop(
AST_OP_MUL,
@AsterSeries.1.n@,
@Term.n@
);
@}
| Term TOK_SYM_ASTER Term
@{
@i @AsterSeries.n@ = ast_make_binop(
AST_OP_MUL,
@Term.0.n@,
@Term.1.n@
);
@}
;
OrSeries
: OrSeries TOK_KEY_OR Term
@{
@i @OrSeries.0.n@ = ast_make_binop(
AST_OP_OR,
@OrSeries.1.n@,
@Term.n@
);
@}
| Term TOK_KEY_OR Term
@{
@i @OrSeries.n@ = ast_make_binop(
AST_OP_OR,
@Term.0.n@,
@Term.1.n@
);
@}
;
DotSeries
/* left-recursion: left-assoc
: DotSeries TOK_SYM_DOT Term
@{
@i @DotSeries.0.n@ = ast_make_binop(
AST_OP_CONS,
@DotSeries.1.n@,
@Term.n@
);
@}*/
/* left-recursion: right-assoc */
: Term TOK_SYM_DOT DotSeries
@{
@i @DotSeries.0.n@ = ast_make_binop(
AST_OP_CONS,
@Term.n@,
@DotSeries.1.n@
);
@}
| Term TOK_SYM_DOT Term
@{
@i @DotSeries.n@ = ast_make_binop(
AST_OP_CONS,
@Term.0.n@,
@Term.1.n@
);
@}
;
CondExprSeries
: CondExprSeries CondContentExpr
@{
@i @CondExprSeries.0.casecount@ =
@CondExprSeries.1.casecount@ + 1
;
@i @CondExprSeries.0.cases@ = ast_make_condcasearr_expand(
@CondExprSeries.1.casecount@,
@CondExprSeries.1.cases@,
@CondContentExpr.n@
);
@}
| CondContentExpr
@{
@i @CondExprSeries.casecount@ = 1;
@i @CondExprSeries.cases@ = ast_make_condcasearr(
@CondContentExpr.n@
);
@}
;
CondContentExpr
: Expr TOK_SYM_TILDE Lexpr TOK_SYM_ARROW Expr TOK_SYM_SEMI
@{
@i @CondContentExpr.n@ = ast_make_condstruc(
@Expr.0.n@,
@Lexpr.n@,
@Expr.1.n@
);
@}
| Expr TOK_SYM_ARROW Expr TOK_SYM_SEMI
@{
@i @CondContentExpr.n@ = ast_make_condcase(
@Expr.0.n@,
@Expr.1.n@
);
@}
;
Lexpr
/* left-recursion = left-associativity
: Lexpr TOK_SYM_DOT Lterm
@{
@i @Lexpr.0.n@ = ast_make_binop(
AST_OP_CONS,
@Lexpr.1.n@,
@Lterm.n@
);
@}*/
/* right-recursion = right-associativity */
: Lterm TOK_SYM_DOT Lexpr
@{
@i @Lexpr.0.n@ = ast_make_binop(
AST_OP_CONS,
@Lterm.n@,
@Lexpr.1.n@
);
@}
| Lterm
@{
@i @Lexpr.n@ = @Lterm.n@;
@}
;
Lterm
: TOK_SYM_PARBEG Lexpr TOK_SYM_PAREND
@{
@i @Lterm.n@ = @Lexpr.n@;
@}
| TOK_IDENT /* Variablendefinition */
@{
@i @Lterm.n@ = ast_make_strucvardef(
@TOK_IDENT.name@
);
free(@TOK_IDENT.name@);
@}
| TOK_SYM_USCORE
@{
@i @Lterm.n@ = ast_make_consumer();
@}
;
/* vim: set ft=lex: */
%option noyywrap
%{
#include "parser.h"
#include "common.h"
#include "astmake.h"
#ifdef __GNUC__
static void yyunput(int c, register char * yy_bp) __attribute__((unused));
static int input(void) __attribute__((unused));
#endif
%}
LCASE [a-z]
UCASE [A-Z]
DIGIT [0-9]
HEXDIGIT [0-9A-Fa-f]
ALPHANUM [a-zA-Z0-9]
IDFIRST [a-zA-Z]
IDREST [a-zA-Z0-9]
%%
";" return TOK_SYM_SEMI;
"(" return TOK_SYM_PARBEG;
")" return TOK_SYM_PAREND;
"," return TOK_SYM_COMMA;
"=" return TOK_SYM_EQUALS;
"~" return TOK_SYM_TILDE;
"->" return TOK_SYM_ARROW;
"-" return TOK_SYM_MINUS;
"+" return TOK_SYM_PLUS;
"*" return TOK_SYM_ASTER;
"." return TOK_SYM_DOT;
">" return TOK_SYM_GT;
"_" return TOK_SYM_USCORE;
"cond" return TOK_KEY_COND;
"end" return TOK_KEY_END;
"not" return TOK_KEY_NOT;
"or" return TOK_KEY_OR;
{DIGIT}+ return TOK_NUMBER; @{
@TOK_NUMBER.val@ = lex_dectoint(yytext);
@}
{DIGIT}{HEXDIGIT}*"H" return TOK_NUMBER; @{
@TOK_NUMBER.val@ = lex_hextoint(yytext);
@}
{IDFIRST}{IDREST}* return TOK_IDENT; @{
@TOK_IDENT.name@ = strdup(yytext);
@}
"//".* ;
[ \t\n\r]+ ;
. lexerror("illegal token");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment