-
Notifications
You must be signed in to change notification settings - Fork 2
/
input.y
142 lines (118 loc) · 3.97 KB
/
input.y
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
%package main # Set the package of the generated file to "main"
%import scanner fmt os strconv # import (
# scanner
# fmt
# os
# strconv
# )
# Replace the default { $$ = $1 } rule code with this custom code.
%defaultcode {
fmt.Println("Default code. Assigning", $1, " to ", $$, "."); $$ = $1
}
# Define the custom value type for tokens
%union {
fval float
ival int
op func(float)float
}
# Associate the "floating" terminal with the type of fval float
%token<fval> floating
# Associate the "integer" terminal with the type of ival int
%token<ival> integer
# Associate the "Calc", "Num", "Mult", and "Add" nonterminals with the type of fval float
%type<fval> Calc Num Mult Add
# Associate the "MultA" and "AddA" nonterminals with the type of op func(float)float
%type<op> MultA AddA
%%
Calc : Add # This will use the code in %defaultcode
;
Mult : Num MultA { fmt.Println("1. Found Mult->'*' Num."); $$ = $2($1) }
;
MultA : '*' Mult { fmt.Println("2. Found MultA->'*' Mult."); $$ = mult($2) }
| '/' Mult { fmt.Println("3. Found MultA->'/' Mult."); $$ = div($2) }
| { fmt.Println("4. Found MultA->{}."); $$ = noop }
;
Add : Mult AddA { fmt.Println("5. Found Add->Mult AddA."); $$ = $2($1) }
;
AddA : '+' Add { fmt.Println("6. Found AddA->'+' Add"); $$ = plus($2) }
| '-' Add { fmt.Println("7. Found AddA->'-' Add"); $$ = minus($2) }
| { fmt.Println("8. Found AddA->{}"); $$ = noop}
;
Num : floating { fmt.Println("9. Found Num->floating. Forwarding value", $1); $$ = float($1) }
| integer { fmt.Println("10. Found Num->integer. Forwarding value", $1); $$ = float($1) }
;
%%
// Define the end-of-file token used by the scanner
const (
EOF = yyUSER + 1
)
// Define functions used by the grammar above
func mult(m float) func(float)float {
return func(f float)float {
return f * m
}
}
func div(m float) func(float)float {
return func(f float)float {
return f / m
}
}
func plus(m float) func(float)float {
return func(f float)float {
return f + m
}
}
func minus(m float) func(float)float {
return func(f float)float {
return f - m
}
}
func noop(m float) float {
return m
}
// Entry point for executable
func main() {
reader := os.Stdin
for true {
var s scanner.Scanner
s.Init(reader)
// Define a scanner function for the yyparse function
nextWord := func(v *yystype)int {
i := s.Scan()
switch i {
case scanner.Float:
// Set the value of the string conversion to the float slot
v.fval, _ = strconv.Atof(s.TokenText())
return floating
case scanner.Int:
// Set the value of the string conversion to the int slot
v.ival, _ = strconv.Atoi(s.TokenText())
return integer
case scanner.Ident:
// Return EOF for the token "eof"
if s.TokenText() == "eof" {return EOF}
return -1
case scanner.String:
return -1
case scanner.Char:
return -1
case scanner.RawString:
return -1
case scanner.Comment:
return -1
case scanner.EOF:
return EOF
default:
return i
}
return -1
}
// Print the result if the parser recognized the input
// Otherwise, print a colloquial but unhelpful message
if ok, result := yyparse(EOF, nextWord); ok {
fmt.Println("Result:", result)
} else {
fmt.Println("Can't parse that, dude.")
}
}
}