Skip to content

Instantly share code, notes, and snippets.

@RavuAlHemio
Created April 1, 2012 14:35
Show Gist options
  • Save RavuAlHemio/2275639 to your computer and use it in GitHub Desktop.
Save RavuAlHemio/2275639 to your computer and use it in GitHub Desktop.
scanner/parser, Lex/Yacc edition
/* vim: set ft=yacc: */
%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
%{
#include "common.h"
#include "astmake.h"
extern ast_generic_node *ast_root;
%}
%union {
char *sval;
numeric_type numval;
ast_generic_node *n;
struct
{
size_t argcount;
char **argnames;
} argnames;
struct
{
size_t argcount;
ast_generic_node **argexprs;
} args;
struct
{
size_t casecount;
ast_generic_node **cases;
} cases;
}
/*@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
{
ast_root = $<n>$ = ast_make_program_expand(
$<n>1,
$<n>2
);
}
| Funcdef TOK_SYM_SEMI
{
ast_root = $<n>$ = ast_make_program($<n>1);
}
;
Funcdef
: TOK_IDENT /* Funktionsname */
TOK_SYM_PARBEG ParamNames TOK_SYM_PAREND /* Parameter */
TOK_SYM_EQUALS Expr /* Definition */
{
$<n>$ = ast_make_funcdef(
$<sval>1,
$<argnames>3.argcount,
$<argnames>3.argnames,
$<n>6
);
free($<sval>1);
}
| TOK_IDENT
TOK_SYM_PARBEG TOK_SYM_PAREND /* parameterlos */
TOK_SYM_EQUALS Expr
{
$<n>$ = ast_make_funcdef(
$<sval>1,
0, NULL,
$<n>5
);
free($<sval>1);
}
;
ParamNames
: ParamNames TOK_SYM_COMMA TOK_IDENT
{
$<argnames>$.argcount = $<argnames>1.argcount + 1;
$<argnames>$.argnames = ast_make_argnames_expand(
$<argnames>1.argcount,
$<argnames>1.argnames,
$<sval>3
);
free($<sval>3);
}
| TOK_IDENT
{
$<argnames>$.argcount = 1;
$<argnames>$.argnames = ast_make_argnames($<sval>1);
free($<sval>1);
}
;
Expr
: TOK_KEY_COND CondExprSeries TOK_SYM_ARROW Expr TOK_KEY_END
{
$<n>$ = ast_make_cond(
$<cases>2.casecount,
$<cases>2.cases,
$<n>4
);
}
| TOK_KEY_COND TOK_SYM_ARROW Expr TOK_KEY_END
{
/*
Don't bother making a conditional construction here.
Just pass the expression upwards.
*/
$<n>$ = $<n>3;
}
| Term
{
$<n>$ = $<n>1;
}
| MinusNotSeries
{
$<n>$ = $<n>1;
}
| PlusSeries
{
$<n>$ = $<n>1;
}
| AsterSeries
{
$<n>$ = $<n>1;
}
| OrSeries
{
$<n>$ = $<n>1;
}
| DotSeries
{
$<n>$ = $<n>1;
}
| Term TOK_SYM_GT Term
{
$<n>$ = ast_make_binop(AST_OP_GT, $<n>1, $<n>3);
}
| Term TOK_SYM_EQUALS Term
{
$<n>$ = ast_make_binop(AST_OP_EQUAL, $<n>1, $<n>3);
}
;
Term
: TOK_SYM_PARBEG Expr TOK_SYM_PAREND
{
$<n>$ = $<n>2;
}
| TOK_NUMBER
{
$<n>$ = ast_make_number($<numval>1);
}
| TOK_IDENT TOK_SYM_PARBEG TOK_SYM_PAREND
{
$<n>$ = ast_make_funccall(
$<sval>1,
0, NULL
);
free($<sval>1);
}
| TOK_IDENT TOK_SYM_PARBEG Params TOK_SYM_PAREND
{
$<n>$ = ast_make_funccall(
$<sval>1,
$<args>3.argcount, $<args>3.argexprs
);
free($<sval>1);
}
| TOK_IDENT
{
$<n>$ = ast_make_varacc($<sval>1);
free($<sval>1);
}
;
Params
: Params TOK_SYM_COMMA Expr
{
$<args>$.argcount = $<args>1.argcount + 1;
$<args>$.argexprs = ast_make_argexprs_expand(
$<args>1.argcount,
$<args>1.argexprs,
$<n>3
);
}
| Expr
{
$<args>$.argcount = 0;
$<args>$.argexprs = ast_make_argexprs($<n>1);
}
;
MinusNotSeries
: TOK_SYM_MINUS MinusNotSeries
{
$<n>$ = ast_make_unop(
AST_OP_MINUS, $<n>2
);
}
| TOK_KEY_NOT MinusNotSeries
{
$<n>$ = ast_make_unop(
AST_OP_NOT, $<n>2
);
}
| TOK_SYM_MINUS Term
{
$<n>$ = ast_make_unop(
AST_OP_MINUS, $<n>2
);
}
| TOK_KEY_NOT Term
{
$<n>$ = ast_make_unop(
AST_OP_NOT, $<n>2
);
}
;
PlusSeries
: PlusSeries TOK_SYM_PLUS Term
{
$<n>$ = ast_make_binop(
AST_OP_ADD,
$<n>1,
$<n>3
);
}
| Term TOK_SYM_PLUS Term
{
$<n>$ = ast_make_binop(
AST_OP_ADD,
$<n>1,
$<n>3
);
}
;
AsterSeries
: AsterSeries TOK_SYM_ASTER Term
{
$<n>$ = ast_make_binop(
AST_OP_MUL,
$<n>1,
$<n>3
);
}
| Term TOK_SYM_ASTER Term
{
$<n>$ = ast_make_binop(
AST_OP_MUL,
$<n>1,
$<n>3
);
}
;
OrSeries
: OrSeries TOK_KEY_OR Term
{
$<n>$ = ast_make_binop(
AST_OP_MUL,
$<n>1,
$<n>3
);
}
| Term TOK_KEY_OR Term
{
$<n>$ = ast_make_binop(
AST_OP_MUL,
$<n>1,
$<n>3
);
}
;
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@
);
@}*/
/* right-recursion: right-assoc */
: Term TOK_SYM_DOT DotSeries
{
$<n>$ = ast_make_binop(
AST_OP_CONS,
$<n>1,
$<n>3
);
}
| Term TOK_SYM_DOT Term
{
$<n>$ = ast_make_binop(
AST_OP_CONS,
$<n>1,
$<n>3
);
}
;
CondExprSeries
: CondExprSeries CondContentExpr
{
$<cases>$.casecount =
$<cases>1.casecount + 1
;
$<cases>$.cases = ast_make_condcasearr_expand(
$<cases>1.casecount,
$<cases>1.cases,
$<n>2
);
}
| CondContentExpr
{
$<cases>$.casecount = 1;
$<cases>$.cases = ast_make_condcasearr(
$<n>1
);
}
;
CondContentExpr
: Expr TOK_SYM_TILDE Lexpr TOK_SYM_ARROW Expr TOK_SYM_SEMI
{
$<n>$ = ast_make_condstruc(
$<n>1,
$<n>3,
$<n>5
);
}
| Expr TOK_SYM_ARROW Expr TOK_SYM_SEMI
{
$<n>$ = ast_make_condcase(
$<n>1,
$<n>3
);
}
;
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
{
$<n>$ = ast_make_binop(
AST_OP_CONS,
$<n>1,
$<n>3
);
}
| Lterm
{
$<n>$ = $<n>1;
}
;
Lterm
: TOK_SYM_PARBEG Lexpr TOK_SYM_PAREND
{
$<n>$ = $<n>1;
}
| TOK_IDENT /* Variablendefinition */
{
$<n>$ = ast_make_strucvardef(
$<sval>1
);
free($<sval>1);
}
| TOK_SYM_USCORE
{
$<n>$ = ast_make_consumer();
}
;
/* vim: set ft=lex: */
%option noyywrap
%{
#include "common.h"
#include "astmake.h"
#include "parser.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}+ yylval.numval = lex_dectoint(yytext); return TOK_NUMBER;
{DIGIT}{HEXDIGIT}*"H" yylval.numval = lex_hextoint(yytext); return TOK_NUMBER;
{IDFIRST}{IDREST}* yylval.sval = strdup(yytext); return TOK_IDENT;
"//".* ;
[ \t\n\r]+ ;
. lexerrorv("illegal tokens: '%s'", yytext);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment