summaryrefslogtreecommitdiff
path: root/ipl/packs/ibpag2/sample.ibp
blob: ab8358f6072d5d128bc5e05401213884bb5f7d84 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#
# Sample Ibpag2 grammar file.
#

#
# The code between %{ and %} gets copied directly.  Note the Iconish
# comment syntax.
#
%{

# Note:  If IIDEBUG is defined in the output file, debugging messages
# about the stacks and actions get displayed.
#
$define IIDEBUG 1

%}

#
# Here we declare the tokens returned by the lexical analyzer.
# Precedences increase as we go on.  Note how (unlike YACC), tokens
# are separated by commas.  Note also how UMINUS is used only for its
# %prec later.
#
%token NUMBER
%left '+', '-'
%left '*', '/'
%right UMINUS

%%

#
# After this point, and up to the next %%, we have the grammar itself.
# By default, the start symbol is the left-hand side of the first
# rule. 
#

lines	:	lines, expr, '\n'	{ write($2) }
	|	lines, '\n'
	|	epsilon	 # Note use of epsilon/error tokens.
	|	error, '\n'		{
					  write("syntax error; try again:")
					  # like YACC's yyerrok macro
					  iierrok
					}
	;

expr	:	expr, '+', expr	{ return $1 + $3 }
	|	expr, '-', expr	{ return $1 - $3 }
	|	expr, '*', expr	{ return $1 * $3 }
	|	expr, '/', expr	{ return $1 / $3 }
	|	'(', expr, ')'	{ return $2 }
	|	'-', expr %prec UMINUS	{ return -$2 }
	|	NUMBER		{ return $1 }
	;

%%

#
# From here on, code gets copied directly to the output file.  We are
# no longer in the grammar proper.
#

#
# The lexical analyzer must be called iilex, with the module name
# appended (if there is one).  It must take one argument, infile (an
# input stream).  It must be a generator, and fail on EOF (not return
# something <= 0, as is the case for YACC + Lex).  Iilval holds the
# literal string value of the token just suspended by iilex().
#
procedure iilex(infile)

    local nextchar, c, num
    initial {
	# Here's where you'd initialize any %{ globals %} declared
	# above.
    }

    nextchar := create !(!infile || "\n" || "\n")

    c := @nextchar | fail
    repeat {
	if any(&digits, c) then {
	    if not (\num ||:= c) then
		num := c
	} else {
	    if iilval := \num then {
		suspend NUMBER
		num := &null
	    }
	    if any('+-*/()\n', c) then {
		iilval := c
		suspend ord(c)
	    } else {
		if not any(' \t', c) then {
		    # deliberate error - will be handled later
		    suspend &null
		}
	    }
	}
	c := @nextchar | break
    }
    if iilval := \num then {
	return NUMBER
	num := &null
    }

end

procedure main()
    return iiparse(&input, 1)
end