home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programmer 7500
/
MAX_PROGRAMMERS.iso
/
INFO
/
AWK
/
AWK320SR.ZIP
/
AWKYACC.Y
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
NeXTSTEP
RISC OS/Acorn
UTF-8
Wrap
Lex Description
|
1991-04-28
|
22.7 KB
|
1,087 lines
%{
/*
* Awk syntactical analyser and pseudo code generator
*
* Copyright (C) 1988, 1989, 1990, 1991 by Rob Duff
* All rights reserved
*/
#include <stddef.h>
#include <alloc.h>
#include <mem.h>
#include "awk.h"
#include "awklex.h"
%}
%union
{
int ival;
double dval;
char *sptr;
FUNC *uptr;
void *vptr;
}
%token T_EOF
%token T_EOL
%token T_BEGIN
%token T_END
%token T_IF
%token T_ELSE
%token T_FOR
%token T_DO
%token T_DONE
%token T_WHILE
%token T_BREAK
%token T_CONTINUE
%token T_FUNCTION
%token T_RETURN
%token T_NEXT
%token T_EXIT
%token T_PRINT
%token T_PRINTF
%token T_INDEX
%token T_SRAND
%token T_CLOSE
%token T_SPLIT
%token T_MATCH
%token T_DELETE
%token T_SUBSTR
%token T_SPRINTF
%token T_GETLINE
%token <ival> T_SUB
%token <vptr> T_USER
%token <vptr> T_NAME
%token <sptr> T_SCON
%token <dval> T_DCON
%token <ival> T_FUNC0
%token <ival> T_FUNC1
%token <ival> T_FUNC2
%right T_CREATE T_APPEND
%right <ival> T_STORE
%left '?' ':'
%nonassoc T_LIOR
%nonassoc T_LAND
%nonassoc T_IN
%nonassoc '~' T_NOMATCH
%nonassoc <ival> T_RELOP '<' '>'
%left T_CONCAT
%left '+' '-'
%left '*' '/'
%right T_SIGN
%right '!'
%right '^'
%left <ival> T_INCOP
%right '$'
%nonassoc T_GROUP
%type <ival> pattern_expression pattern_disjunction pattern_conjunction
%type <ival> expression print_expression conditional print_conditional
%type <ival> print_disjunction disjunction conjunction print_conjunction
%type <ival> membership print_membership match print_match
%type <ival> match_relation relation match_concatenation
%type <ival> concatenation arithmetic term unary exponential factor
%type <ival> optional_argument_list optional_expression
%type <ival> optional_print_list expression_list print_expression_list
%type <ival> field_zero_match regular_expression
%type <uptr> declaration
%type <vptr> body action pattern pattern_predicate
%type <vptr> optional_parameter_list parameter_list
%%
pattern_action_list:
pattern_action_list eos pattern_action
| pattern_action
;
pattern_action:
T_FUNCTION declaration body {
yydisplay = NULL;
$2->pcode = $3;
}
| T_BEGIN action {
if (beginend == NULL)
beginact = beginend = genact($2);
else
beginend = beginend->cnext = genact($2);
}
| T_END action {
if (endend == NULL)
endact = endend = genact($2);
else
endend = endend->cnext = genact($2);
}
| pattern action {
enroll($1, $2);
}
| pattern {
genfield(0);
lastop(C_PLUCK);
genfcon(0);
gencall(P_PRINT, 2);
genbyte(C_END);
enroll($1, gencode());
}
| action {
enroll(genrule(NULL, NULL), $1);
}
|
;
declaration:
T_USER '(' optional_parameter_list ')' {
yydisplay = $3;
$$ = ((IDENT*)($1))->vfunc = newfunction();
}
;
optional_parameter_list:
parameter_list {
$$ = $1;
}
| {
$$ = 0;
}
;
parameter_list:
parameter_list comma T_NAME {
$$ = newelement($1, $3);
}
| T_NAME {
$$ = newelement(NULL, $1);
}
;
body:
'{' {
pushstack(L_MARK);
} statement_list '}' {
popstack(L_MARK);
if (stacktop != stackbot + MAXSTACK)
yyerror("body jump stack");
if (lastcode() != C_RETURN) {
genaddr(lookfor(nul));
genbyte(C_LOAD);
genbyte(C_RETURN);
}
genbyte(C_END);
$$ = gencode();
}
;
pattern:
pattern_predicate comma pattern_predicate {
$$ = genrule($1, $3);
}
| pattern_predicate {
$$ = genrule($1, NULL);
}
;
pattern_predicate:
pattern_disjunction {
genbyte(C_END);
$$ = gencode();
}
;
pattern_disjunction:
pattern_conjunction
| pattern_disjunction T_LIOR eol {
yyl1 = getlabel();
pushlabel(L_NORMAL, yyl1);
genjump(C_OJMP, yyl1);
} pattern_conjunction {
yyl1 = poplabel();
genlabel(yyl1);
putlabel(yyl1);
$$ = S_LONG;
}
;
pattern_conjunction:
pattern_expression
| pattern_conjunction T_LAND eol {
yyl1 = getlabel();
pushlabel(L_NORMAL, yyl1);
genjump(C_AJMP, yyl1);
} pattern_expression {
yyl1 = poplabel();
genlabel(yyl1);
putlabel(yyl1);
$$ = S_LONG;
}
;
pattern_expression:
field_zero_match
| '!' field_zero_match {
genbyte(C_NOT);
$$ = S_SHORT;
}
| '(' pattern_disjunction ')' {
$$ = $2;
}
| '!' '(' pattern_disjunction ')' {
genbyte(C_NOT);
$$ = S_SHORT;
}
| membership
;
field_zero_match:
regular_expression {
genfield(0);
lastop(C_PLUCK);
genbyte(C_SWAP);
genbyte(C_MAT);
$$ = S_SHORT;
}
;
action:
'{' {
pushstack(L_MARK);
} statement_list '}' {
popstack(L_MARK);
if (stacktop != stackbot + MAXSTACK)
yyerror("action jump stack");
genbyte(C_END);
$$ = gencode();
}
;
statement_list:
statement_list eos else_part
| statement
;
else_part:
T_ELSE eol {
yyl1 = toploop(L_ELSE);
if (yyl1 < 0)
yyerror("syntax error");
yyl1 = getloop(L_ELSE);
pushlabel(L_ELSE, yyl1);
yyl2 = getlabel();
genjump(C_JUMP, yyl2);
genlabel(yyl1);
uselabel(yyl1, yyl2);
putlabel(yyl2);
} statement
| {
while (stackptr->sclass >= L_FOR)
popstack(stackptr->sclass);
} statement
;
statement:
expression {
gendrop();
}
| '{' {
pushstack(L_MARK);
} statement_list {
popstack(L_MARK);
} '}'
| T_IF '(' expression ')' eol {
yyl1 = getlabel();
pushlabel(L_ELSE, yyl1);
genjump(C_FJMP, yyl1);
} statement
| T_WHILE {
yyl1 = getlabel();
yyl2 = getlabel();
pushlabel(L_BREAK, yyl1);
pushlabel(L_CONTINUE, yyl2);
pushstack(L_WHILE);
genlabel(yyl2);
} '(' expression ')' eol {
yyl1 = toploop(L_BREAK);
genjump(C_FJMP, yyl1);
} statement
| T_DO eol {
yyl1 = getlabel();
yyl2 = getlabel();
yyl3 = getlabel();
pushlabel(L_NORMAL, yyl1);
pushlabel(L_BREAK, yyl2);
pushlabel(L_CONTINUE, yyl3);
pushstack(L_DONE);
genlabel(yyl1);
yydone = 1;
} statement
| T_DONE {
popstack(L_DONE);
yyl1 = toploop(L_CONTINUE);
genlabel(yyl1);
yydone = 0;
} '(' expression ')' {
yyl1 = poplabel();
yyl2 = poplabel();
yyl3 = poplabel();
genjump(C_TJMP, yyl3);
genlabel(yyl2);
putlabel(yyl1);
putlabel(yyl2);
putlabel(yyl3);
}
| T_FOR '(' variable T_IN variable_name ')' eol {
yyl1 = getlabel();
yyl2 = getlabel();
pushlabel(L_BREAK, yyl1);
pushlabel(L_CONTINUE, yyl2);
pushstack(L_FOR);
genbyte(C_LOAD);
genlabel(yyl2);
genjump(C_IJMP, yyl1);
} statement
| T_FOR '(' optional_statement ';' {
yyl1 = getlabel();
yyl2 = getlabel();
pushlabel(L_BREAK, yyl1);
pushlabel(L_CONTINUE, yyl2);
pushstack(L_FOR);
yyl1 = getlabel();
yyl2 = getlabel();
pushlabel(L_NORMAL, yyl1);
pushlabel(L_NORMAL, yyl2);
genlabel(yyl1);
} for_test
| T_BREAK {
yyl1 = toploop(L_BREAK);
if (yyl1 < 0) {
yyerror("invalid break");
YYERROR;
}
genjump(C_JUMP, yyl1);
}
| T_CONTINUE {
yyl1 = toploop(L_CONTINUE);
if (yyl1 < 0) {
yyerror("invalid continue");
YYERROR;
}
genjump(C_JUMP, yyl1);
}
| T_RETURN return_expression {
genbyte(C_RETURN);
}
| T_SRAND '(' optional_expression ')' {
gencall(P_SRAND, $3);
}
| T_PRINT '(' expression_list ')' output_file {
gencall(P_PRINT, $3+1);
}
| T_PRINT optional_print_list output_file {
gencall(P_PRINT, $2+1);
}
| T_PRINTF '(' expression_list ')' output_file {
gencall(P_PRINTF, $3+1);
}
| T_PRINTF print_expression_list output_file {
gencall(P_PRINTF, $2+1);
}
| T_CLOSE '(' expression ')' {
gencall(P_CLOSE, 1);
}
| T_DELETE variable_name '[' expression_list ']' {
if ($4 > 1)
gencall(P_JOIN, $4);
gencall(P_DELETE, 2);
}
| T_NEXT {
gencall(P_NEXT, 0);
}
| T_EXIT optional_expression {
gencall(P_EXIT, $2);
}
|
;
optional_expression:
expression {
$$ = 1;
}
| {
$$ = 0;
}
;
for_test:
';' {
yyl1 = toploop(L_NORMAL);
yyl2 = toploop(L_CONTINUE);
genjump(C_JUMP, yyl1);
genlabel(yyl2);
} optional_statement ')' eol {
yyl1 = poplabel();
yyl2 = poplabel();
genlabel(yyl1);
putlabel(yyl1);
putlabel(yyl2);
} statement
| expression ';' {
yyl1 = toploop(L_BREAK);
genjump(C_FJMP, yyl1);
} for_next
;
for_next:
')' eol {
yyl1 = poplabel();
yyl2 = poplabel();
yyl3 = toploop(L_CONTINUE);
uselabel(yyl3, yyl2);
putlabel(yyl1);
putlabel(yyl2);
} statement
| {
yyl1 = toploop(L_NORMAL);
yyl2 = toploop(L_CONTINUE);
genjump(C_JUMP, yyl1);
genlabel(yyl2);
} expression ')' eol {
yyl1 = poplabel();
yyl2 = poplabel();
gendrop();
genjump(C_JUMP, yyl2);
genlabel(yyl1);
putlabel(yyl1);
putlabel(yyl2);
} statement
;
optional_statement:
expression {
gendrop();
}
|
;
optional_print_list:
print_expression_list {
$$ = $1;
}
| {
genfield(0);
lastop(C_PLUCK);
$$ = 1;
}
;
return_expression:
expression
| {
genaddr(lookfor(nul));
genbyte(C_LOAD);
}
;
output_file:
'>' factor {
gencall(P_CREATE, 1);
}
| T_APPEND factor {
gencall(P_APPEND, 1);
}
| {
genfcon(0);
}
;
input_file:
'<' factor {
gencall(P_OPEN, 1);
}
| {
genfcon(1);
}
;
regular_expression:
'/' {
genrcon(regexp(1));
$$ = S_REGEXP;
}
;
print_expression:
variable T_STORE print_expression {
genstore($2);
$$ = $3;
}
| print_conditional
;
print_conditional:
print_disjunction {
if ($1 == S_LONG)
genbyte(C_IS);
$$ = S_SHORT;
}
| print_disjunction '?' {
yyl1 = getlabel();
yyl2 = getlabel();
pushlabel(L_NORMAL, yyl1);
pushlabel(L_NORMAL, yyl2);
genjump(C_FJMP, yyl2);
} print_expression ':' {
yyl1 = poplabel();
yyl2 = toploop(L_NORMAL);
genjump(C_JUMP, yyl2);
genlabel(yyl1);
putlabel(yyl1);
} print_expression {
yyl1 = poplabel();
genlabel(yyl1);
putlabel(yyl1);
$$ = S_NUMBER;
}
;
print_disjunction:
print_conjunction
| print_disjunction T_LIOR eol {
yyl1 = getlabel();
pushlabel(L_NORMAL, yyl1);
genjump(C_OJMP, yyl1);
} print_conjunction {
yyl1 = poplabel();
genlabel(yyl1);
putlabel(yyl1);
$$ = S_LONG;
}
;
print_conjunction:
print_membership
| print_conjunction T_LAND eol {
yyl1 = getlabel();
pushlabel(L_NORMAL, yyl1);
genjump(C_AJMP, yyl1);
} print_membership {
yyl1 = poplabel();
genlabel(yyl1);
putlabel(yyl1);
$$ = S_LONG;
}
;
print_membership:
'(' expression_list ')' T_IN {
if ($2 > 1)
gencall(P_JOIN, $2);
} variable_name {
genbyte(C_IN);
$$ = S_SHORT;
}
| print_match T_IN variable_name {
genbyte(C_IN);
$$ = S_SHORT;
}
| print_match
;
print_match:
concatenation
| concatenation '~' match_concatenation {
genbyte(C_MAT);
$$ = S_SHORT;
}
| concatenation T_NOMATCH match_concatenation {
genbyte(C_MAT);
genbyte(C_NOT);
$$ = S_SHORT;
}
;
match_concatenation:
regular_expression
| concatenation
;
print_expression_list:
print_expression_list comma print_expression {
$$ = $1 + 1;
}
| print_expression {
$$ = 1;
}
;
expression:
variable T_STORE expression {
genstore($2);
$$ = $3;
}
| conditional
;
conditional:
disjunction {
if ($1 == S_LONG)
genbyte(C_IS);
$$ = S_SHORT;
}
| disjunction '?' {
yyl1 = getlabel();
yyl2 = getlabel();
pushlabel(L_NORMAL, yyl1);
pushlabel(L_NORMAL, yyl2);
genjump(C_FJMP, yyl2);
} expression ':' {
yyl1 = poplabel();
yyl2 = toploop(L_NORMAL);
genjump(C_JUMP, yyl2);
genlabel(yyl1);
putlabel(yyl1);
} expression {
yyl1 = poplabel();
genlabel(yyl1);
putlabel(yyl1);
$$ = S_NUMBER;
}
;
disjunction:
conjunction
| disjunction T_LIOR eol {
yyl1 = getlabel();
pushlabel(L_NORMAL, yyl1);
genjump(C_OJMP, yyl1);
} conjunction {
yyl1 = poplabel();
genlabel(yyl1);
putlabel(yyl1);
$$ = S_LONG;
}
;
conjunction:
membership
| conjunction T_LAND eol {
yyl1 = getlabel();
pushlabel(L_NORMAL, yyl1);
genjump(C_AJMP, yyl1);
} membership {
yyl1 = poplabel();
genlabel(yyl1);
putlabel(yyl1);
$$ = S_LONG;
}
;
membership:
'(' expression_list ')' T_IN {
if ($2 > 1)
gencall(P_JOIN, $2);
} variable_name {
genbyte(C_IN);
$$ = S_SHORT;
}
| match T_IN variable_name {
genbyte(C_IN);
$$ = S_SHORT;
}
| match
;
match:
relation
| relation '~' match_relation {
genbyte(C_MAT);
$$ = S_SHORT;
}
| relation T_NOMATCH match_relation {
genbyte(C_MAT);
genbyte(C_NOT);
$$ = S_SHORT;
}
;
relation:
concatenation
| concatenation T_RELOP concatenation {
genbyte($2);
$$ = S_SHORT;
}
| concatenation '<' concatenation {
genbyte(C_LT);
$$ = S_SHORT;
}
| concatenation '>' concatenation {
genbyte(C_GT);
$$ = S_SHORT;
}
;
concatenation:
arithmetic
| concatenation arithmetic {
genbyte(C_CAT);
$$ = S_STRING;
}
;
arithmetic:
term
| arithmetic '+' term {
genbyte(C_ADD);
$$ = S_DOUBLE;
}
| arithmetic '-' term {
genbyte(C_SUB);
$$ = S_DOUBLE;
}
;
term:
unary
| term '*' unary {
genbyte(C_MUL);
$$ = S_DOUBLE;
}
| term '/' unary {
genbyte(C_DIV);
$$ = S_DOUBLE;
}
| term '%' unary {
genbyte(C_MOD);
$$ = S_DOUBLE;
}
;
unary:
exponential
| '!' exponential {
genbyte(C_NOT);
$$ = S_DOUBLE;
}
| '-' exponential %prec T_SIGN {
genbyte(C_NEG);
$$ = S_DOUBLE;
}
| '+' exponential %prec T_SIGN {
genbyte(C_NUM);
$$ = S_DOUBLE;
}
;
exponential:
factor
| factor '^' exponential {
genbyte(C_POW);
$$ = S_DOUBLE;
}
;
factor:
T_INCOP variable {
gentwo(C__PRE, $1);
$$ = S_DOUBLE;
}
| variable T_INCOP {
gentwo(C__POST, $2);
$$ = S_DOUBLE;
}
| variable {
if (lastcode() == C_ADDR)
lastop(C_FETCH);
else if (lastcode() == C_FIELD)
lastop(C_PLUCK);
else
genbyte(C_LOAD);
$$ = S_NUMBER;
}
| '(' expression ')' %prec T_GROUP {
$$ = S_NUMBER;
}
| T_DCON {
gendcon($1);
$$ = S_DOUBLE;
}
| T_SCON {
genscon($1);
$$ = S_STRING;
}
| T_USER '(' optional_argument_list ')' {
genuser($1, $3);
$$ = S_NUMBER;
}
| T_FUNC0 '(' ')' {
genbyte($1);
$$ = S_NUMBER;
}
| T_FUNC1 '(' expression ')' {
genbyte($1);
$$ = S_NUMBER;
}
| T_FUNC2 '(' expression comma expression ')' {
genbyte($1);
$$ = S_NUMBER;
}
| T_SUB '(' match_expression comma expression ')' {
genfield(0);
genfield(0);
lastop(C_PLUCK);
gencall($1, 4);
$$ = S_STRING;
}
| T_SUB '(' match_expression comma expression comma variable ')' {
genbyte(C_DUP);
genbyte(C_LOAD);
gencall($1, 4);
$$ = S_STRING;
}
| T_SUB '(' match_expression comma expression comma expression ')' {
genaddr(lookfor(nul));
genbyte(C_SWAP);
gencall($1, 4);
$$ = S_STRING;
}
| T_SPLIT '(' expression comma variable_name ')' {
genaddr(lookfor(fs));
genbyte(C_LOAD);
gencall(P_SPLIT, 3);
$$ = S_DOUBLE;
}
| T_SPLIT '(' expression comma variable_name comma expression ')' {
gencall(P_SPLIT, 3);
$$ = S_DOUBLE;
}
| T_MATCH '(' expression comma match_expression ')' {
gencall(P_MATCH, 2);
$$ = S_SHORT;
}
| T_INDEX '(' expression ')' {
genfield(0);
lastop(C_PLUCK);
genbyte(C_SWAP);
gencall(P_INDEX, 2);
$$ = S_DOUBLE;
}
| T_INDEX '(' expression comma expression ')' {
gencall(P_INDEX, 2);
$$ = S_DOUBLE;
}
| T_SUBSTR '(' expression comma expression ')' {
gencall(P_SUBSTR, 2);
$$ = S_STRING;
}
| T_SUBSTR '(' expression comma expression comma expression ')' {
gencall(P_SUBSTR, 3);
$$ = S_STRING;
}
| T_SPRINTF '(' expression_list ')' {
gencall(P_SPRINTF, $3);
$$ = S_DOUBLE;
}
| T_GETLINE variable input_file {
gencall(P_GETLINE, 2);
$$ = S_DOUBLE;
}
| T_GETLINE input_file {
genfield(0);
genbyte(C_SWAP);
gencall(P_GETLINE, 2);
$$ = S_DOUBLE;
}
;
match_relation:
regular_expression
| relation
;
match_expression:
regular_expression
| expression
;
expression_list:
expression_list comma expression {
$$ = $1 + 1;
}
| expression {
$$ = 1;
}
;
optional_argument_list:
expression_list {
$$ = $1;
}
| {
$$ = 0;
}
;
variable:
'$' factor {
if (lastcode() == C_DCON)
genfield(lastdcon());
else
genbyte(C_DOLAR);
}
| variable_name '[' expression_list ']' {
if ($3 > 1)
gencall(P_JOIN, $3);
genbyte(C_SELECT);
}
| variable_name
;
variable_name:
T_NAME {
genaddr($1);
}
;
comma:
',' eol
;
eos:
';'
| T_EOL
;
eol:
T_EOL
|
;
%%
int yydone;
int yyl1, yyl2, yyl3;
LIST *yydisplay;
static int toploop(int);
static int getloop(int);
static int poplabel(void);
static void popstack(int);
static void pushstack(int);
static void pushlabel(int, int);
static void enroll(void*, void*);
static void *newfunction(void);
static void *newelement(void*, void*);
IDENT *lookfor(ITEM *sp)
{
IDENT *vp;
for (vp = ident; vp != NULL; vp = vp->vnext)
if (vp->vitem == sp)
return vp;
return NULL;
}
static void enroll(rule, action)
void *rule;
void *action;
{
if (rulep == NULL) {
rulep = rule;
rules = rulep;
}
else {
rulep->next = rule;
rulep = rule;
}
rulep->next = NULL;
rulep->action = action;
}
static void*
newelement(next, item)
void *next;
void *item;
{
LIST *lp;
lp = yyalloc(sizeof(LIST));
lp->litem = item;
lp->lnext = next;
return lp;
}
static void*
newfunction()
{
int size;
FUNC *fp;
LIST *lp;
size = 0;
lp = yydisplay;
while (lp != NULL) {
size++;
lp = lp->lnext;
}
fp = yyalloc(sizeof(FUNC));
fp->psize = size;
fp->plist = yydisplay;
fp->pcode = NULL;
return fp;
}
static void
pushstack(kind)
{
if (stackptr <= stackbot)
yyerror("Stack overflow");
stackptr--;
stackptr->sclass = kind;
stackptr->svalue.ival = 0;
if (kind == L_MARK || kind == L_DONE) {
stackptr->stype = yydone;
stackptr->svalue.sptr = stacktop;
stacktop = stackptr;
yydone = 0;
}
}
static void popstack(kind)
{
int i, j, class;
while (stackptr < stacktop) {
class = stackptr->sclass;
if ( class == L_FOR || class == L_WHILE) {
stackptr++;
i = poplabel();
j = poplabel();
genjump(C_JUMP, i);
genlabel(j);
putlabel(i);
putlabel(j);
}
else if (class == L_ELSE) {
i = poplabel();
genlabel(i);
putlabel(i);
}
else
yyerror("dangling label");
if (class == kind)
return;
}
if (kind == L_MARK || kind == L_DONE) {
yydone = stackptr->stype;
stacktop = stackptr->svalue.sptr;
stackptr++;
}
else
yyerror("syntax error");
}
static int toploop(int class)
{
ITEM *sp;
int label;
sp = stackptr;
while (sp < stackbot + MAXSTACK)
if (sp->sclass == class) {
label = sp->svalue.ival;
#ifdef LDEBUG
printlabel("top", label);
#endif
return label;
}
else
sp++;
return(-1);
}
static int getloop(class)
{
while (stackptr < stacktop) {
if (stackptr->sclass == class)
return poplabel();
else
popstack(stackptr->sclass);
}
return(-1);
}
static void
pushlabel(class, label)
{
#ifdef LDEBUG
printlabel("pop", label);
#endif
if (stackptr <= stackbot)
yyerror("Stack overflow");
stackptr--;
stackptr->sclass = class;
stackptr->svalue.ival = label;
}
static int
poplabel()
{
int label;
label = stackptr->svalue.ival;
#ifdef LDEBUG
printlabel("pop", label);
#endif
stackptr++;
return label;
}