hawk.y 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. %{
  2. package hawkc
  3. import (
  4. "bufio"
  5. "fmt"
  6. "io"
  7. "github.com/mibk/hawk/scan"
  8. "github.com/mibk/hawk/value"
  9. )
  10. var (
  11. progName string
  12. ast *Program
  13. defaultAction = &BlockStmt{[]Stmt{&PrintStmt{Fun: "print"}}}
  14. )
  15. %}
  16. %union {
  17. sym string
  18. val value.Value
  19. symlist []string
  20. decl Decl
  21. decllist []Decl
  22. expr Expr
  23. exprlist []Expr
  24. stmt Stmt
  25. stmtlist []Stmt
  26. blockstmt *BlockStmt
  27. }
  28. %type <decl> decl paction funcdecl
  29. %type <symlist> arglist
  30. %type <decllist> decllist
  31. %type <expr> expr oexpr uexpr indexexpr addressable
  32. %type <exprlist> exprlist
  33. %type <stmt> pipeline stmt ostmt ifstmt else if_or_block forstmt foreachstmt
  34. %type <blockstmt> blockstmt
  35. %type <stmtlist> stmtlist
  36. %token <sym> IDENT BOOL STRING PRINT
  37. %token <val> NUM
  38. %token BEGIN END
  39. %token IF ELSE
  40. %token FOR IN BREAK CONTINUE
  41. %token INC DEC
  42. %token ADDEQ SUBEQ MULEQ DIVEQ MODEQ CONCATEQ
  43. %token FUNC RETURN
  44. %right '?' ':'
  45. %left OROR
  46. %left ANDAND
  47. %left EQ NE LE GE '<' '>'
  48. %left '~', NOTMATCH
  49. %left '.'
  50. %left '+' '-'
  51. %left '*' '/' '%'
  52. %%
  53. top:
  54. decllist ';'
  55. {
  56. for _, d := range $1 {
  57. switch d := d.(type) {
  58. case *BeginAction:
  59. ast.Begins = append(ast.Begins, d)
  60. case *EndAction:
  61. ast.Ends = append(ast.Ends, d)
  62. case *PatternAction:
  63. ast.Pactions = append(ast.Pactions, d)
  64. case *FuncDecl:
  65. ast.funcs[d.Name] = d
  66. default:
  67. panic(fmt.Sprintf("unexpected type: %T", d))
  68. }
  69. }
  70. }
  71. decllist:
  72. decl
  73. {
  74. $$ = []Decl{$1}
  75. }
  76. | decllist ';' decl
  77. {
  78. $$ = append($1, $3)
  79. }
  80. decl:
  81. paction
  82. {
  83. $$ = $1
  84. }
  85. | funcdecl
  86. {
  87. $$ = $1
  88. }
  89. paction:
  90. oexpr blockstmt
  91. {
  92. $$ = &PatternAction{$1, $2}
  93. }
  94. | expr
  95. {
  96. $$ = &PatternAction{$1, defaultAction}
  97. }
  98. | BEGIN blockstmt
  99. {
  100. $$ = &BeginAction{$2}
  101. }
  102. | END blockstmt
  103. {
  104. $$ = &EndAction{$2}
  105. }
  106. funcdecl:
  107. FUNC IDENT '(' arglist ')' blockstmt
  108. {
  109. $$ = &FuncDecl{&FuncScope{}, $2, $4, $6}
  110. }
  111. arglist:
  112. {
  113. $$ = nil
  114. }
  115. | IDENT
  116. {
  117. $$ = []string{$1}
  118. }
  119. | arglist ',' IDENT
  120. {
  121. $$ = append($1, $3)
  122. }
  123. blockstmt:
  124. '{' stmtlist osemi '}'
  125. {
  126. $$ = &BlockStmt{$2}
  127. }
  128. stmtlist:
  129. {
  130. $$ = nil
  131. }
  132. | pipeline
  133. {
  134. $$ = []Stmt{$1}
  135. }
  136. | stmtlist ';' pipeline
  137. {
  138. $$ = append($1, $3)
  139. }
  140. pipeline:
  141. stmt
  142. {
  143. $$ = $1
  144. }
  145. | blockstmt
  146. {
  147. $$ = $1
  148. }
  149. | pipeline '|' STRING
  150. {
  151. $$ = &PipeStmt{genDebugInfo(), $1, $3}
  152. }
  153. stmt:
  154. expr
  155. {
  156. $$ = &ExprStmt{$1}
  157. }
  158. | addressable '=' expr
  159. {
  160. $$ = &AssignStmt{genDebugInfo(), nil, $1, $3}
  161. }
  162. // The following 2 rules could be made into one by replacing IDENT/indexexpr with addressable,
  163. // but then there are 3 shift/reduce conflicts.
  164. | IDENT '[' ']' '=' expr
  165. {
  166. $$ = &AssignStmt{genDebugInfo(), nil, &IndexExpr{genDebugInfo(), &Ident{Name: $1}, nil}, $5}
  167. }
  168. | indexexpr '[' ']' '=' expr
  169. {
  170. $$ = &AssignStmt{genDebugInfo(), nil, &IndexExpr{genDebugInfo(), $1, nil}, $5}
  171. }
  172. | addressable ADDEQ expr
  173. {
  174. $$ = &AssignStmt{genDebugInfo(), nil, $1, &BinaryExpr{genDebugInfo(), Add, $1, $3}}
  175. }
  176. | addressable SUBEQ expr
  177. {
  178. $$ = &AssignStmt{genDebugInfo(), nil, $1, &BinaryExpr{genDebugInfo(), Sub, $1, $3}}
  179. }
  180. | addressable MULEQ expr
  181. {
  182. $$ = &AssignStmt{genDebugInfo(), nil, $1, &BinaryExpr{genDebugInfo(), Mul, $1, $3}}
  183. }
  184. | addressable DIVEQ expr
  185. {
  186. $$ = &AssignStmt{genDebugInfo(), nil, $1, &BinaryExpr{genDebugInfo(), Div, $1, $3}}
  187. }
  188. | addressable MODEQ expr
  189. {
  190. $$ = &AssignStmt{genDebugInfo(), nil, $1, &BinaryExpr{genDebugInfo(), Mod, $1, $3}}
  191. }
  192. | addressable CONCATEQ expr
  193. {
  194. $$ = &AssignStmt{genDebugInfo(), nil, $1, &BinaryExpr{genDebugInfo(), Concat, $1, $3}}
  195. }
  196. | addressable INC
  197. {
  198. $$ = &AssignStmt{genDebugInfo(), nil, $1, &BinaryExpr{genDebugInfo(), Add, $1, BasicLit{value.NewNumber(1)}}}
  199. }
  200. | addressable DEC
  201. {
  202. $$ = &AssignStmt{genDebugInfo(), nil, $1, &BinaryExpr{genDebugInfo(), Sub, $1, BasicLit{value.NewNumber(1)}}}
  203. }
  204. | ifstmt
  205. {
  206. $$ = $1
  207. }
  208. | forstmt
  209. {
  210. $$ = $1
  211. }
  212. | foreachstmt
  213. {
  214. $$ = $1
  215. }
  216. | BREAK
  217. {
  218. $$ = &StatusStmt{StatusBreak}
  219. }
  220. | CONTINUE
  221. {
  222. $$ = &StatusStmt{StatusContinue}
  223. }
  224. | RETURN oexpr
  225. {
  226. $$ = &ReturnStmt{X: $2}
  227. }
  228. | PRINT exprlist
  229. {
  230. $$ = &PrintStmt{genDebugInfo(), nil, $1, $2}
  231. }
  232. | PRINT
  233. {
  234. $$ = &PrintStmt{genDebugInfo(), nil, $1, nil}
  235. }
  236. addressable:
  237. IDENT
  238. {
  239. $$ = &Ident{ast, $1}
  240. }
  241. | indexexpr
  242. {
  243. $$ = $1
  244. }
  245. ostmt:
  246. {
  247. $$ = nil
  248. }
  249. | stmt
  250. {
  251. $$ = $1
  252. }
  253. ifstmt:
  254. IF expr blockstmt else
  255. {
  256. $$ = &IfStmt{genDebugInfo(), $2, $3, $4}
  257. }
  258. else:
  259. {
  260. $$ = nil
  261. }
  262. | ELSE if_or_block
  263. {
  264. $$ = $2
  265. }
  266. if_or_block:
  267. ifstmt
  268. {
  269. $$ = $1
  270. }
  271. | blockstmt
  272. {
  273. $$ = $1
  274. }
  275. forstmt:
  276. FOR ostmt ';' oexpr ';' ostmt blockstmt
  277. {
  278. $$ = &ForStmt{genDebugInfo(), $2, $4, $6, $7}
  279. }
  280. | FOR oexpr blockstmt
  281. {
  282. $$ = &ForStmt{genDebugInfo(), nil, $2, nil, $3}
  283. }
  284. foreachstmt:
  285. FOR IDENT IN expr blockstmt
  286. {
  287. $$ = &ForeachStmt{genDebugInfo(), &Ident{Name: $2}, nil, $4, $5}
  288. }
  289. | FOR IDENT ',' IDENT IN expr blockstmt
  290. {
  291. $$ = &ForeachStmt{genDebugInfo(), &Ident{Name: $2}, &Ident{Name: $4}, $6, $7}
  292. }
  293. expr:
  294. uexpr
  295. {
  296. $$ = $1
  297. }
  298. | expr '?' expr ':' expr
  299. {
  300. $$ = &TernaryExpr{genDebugInfo(), $1, $3, $5}
  301. }
  302. | '$' uexpr
  303. {
  304. $$ = &FieldExpr{genDebugInfo(), nil, $2}
  305. }
  306. | expr OROR expr
  307. {
  308. $$ = &BinaryExpr{genDebugInfo(), OrOr, $1, $3}
  309. }
  310. | expr ANDAND expr
  311. {
  312. $$ = &BinaryExpr{genDebugInfo(), AndAnd, $1, $3}
  313. }
  314. | expr EQ expr
  315. {
  316. $$ = &BinaryExpr{genDebugInfo(), Eq, $1, $3}
  317. }
  318. | expr NE expr
  319. {
  320. $$ = &BinaryExpr{genDebugInfo(), NotEq, $1, $3}
  321. }
  322. | expr LE expr
  323. {
  324. $$ = &BinaryExpr{genDebugInfo(), LtEq, $1, $3}
  325. }
  326. | expr GE expr
  327. {
  328. $$ = &BinaryExpr{genDebugInfo(), GtEq, $1, $3}
  329. }
  330. | expr '<' expr
  331. {
  332. $$ = &BinaryExpr{genDebugInfo(), Lt, $1, $3}
  333. }
  334. | expr '>' expr
  335. {
  336. $$ = &BinaryExpr{genDebugInfo(), Gt, $1, $3}
  337. }
  338. | expr '+' expr
  339. {
  340. $$ = &BinaryExpr{genDebugInfo(), Add, $1, $3}
  341. }
  342. | expr '-' expr
  343. {
  344. $$ = &BinaryExpr{genDebugInfo(), Sub, $1, $3}
  345. }
  346. | expr '*' expr
  347. {
  348. $$ = &BinaryExpr{genDebugInfo(), Mul, $1, $3}
  349. }
  350. | expr '/' expr
  351. {
  352. $$ = &BinaryExpr{genDebugInfo(), Div, $1, $3}
  353. }
  354. | expr '%' expr
  355. {
  356. $$ = &BinaryExpr{genDebugInfo(), Mod, $1, $3}
  357. }
  358. | expr '.' expr
  359. {
  360. $$ = &BinaryExpr{genDebugInfo(), Concat, $1, $3}
  361. }
  362. | expr '~' expr
  363. {
  364. $$ = &MatchExpr{genDebugInfo(), $1, $3, true}
  365. }
  366. | expr NOTMATCH expr
  367. {
  368. $$ = &MatchExpr{genDebugInfo(), $1, $3, false}
  369. }
  370. oexpr:
  371. {
  372. $$ = nil
  373. }
  374. | expr
  375. {
  376. $$ = $1
  377. }
  378. uexpr:
  379. NUM
  380. {
  381. $$ = BasicLit{$1}
  382. }
  383. | STRING
  384. {
  385. $$ = BasicLit{value.NewString($1)}
  386. }
  387. | BOOL
  388. {
  389. $$ = BasicLit{value.NewBool($1 == "true")}
  390. }
  391. | '+' uexpr
  392. {
  393. $$ = $2
  394. }
  395. | '-' uexpr
  396. {
  397. $$ = &UnaryExpr{genDebugInfo(), Minus, $2}
  398. }
  399. | '!' uexpr
  400. {
  401. $$ = &UnaryExpr{genDebugInfo(), Not, $2}
  402. }
  403. | '(' expr ')'
  404. {
  405. $$ = $2
  406. }
  407. | IDENT
  408. {
  409. $$ = &Ident{Name: $1}
  410. }
  411. | IDENT '(' ')'
  412. {
  413. $$ = &CallExpr{genDebugInfo(), $1, nil}
  414. }
  415. | IDENT '(' exprlist ocomma ')'
  416. {
  417. $$ = &CallExpr{genDebugInfo(), $1, $3}
  418. }
  419. | '[' ']'
  420. {
  421. $$ = &ArrayLit{}
  422. }
  423. | '[' exprlist ocomma ']'
  424. {
  425. $$ = &ArrayLit{$2}
  426. }
  427. | indexexpr
  428. {
  429. $$ = $1
  430. }
  431. indexexpr:
  432. IDENT '[' expr ']'
  433. {
  434. $$ = &IndexExpr{genDebugInfo(), &Ident{Name: $1}, $3}
  435. }
  436. | indexexpr '[' expr ']'
  437. {
  438. $$ = &IndexExpr{genDebugInfo(), $1, $3}
  439. }
  440. exprlist:
  441. expr
  442. {
  443. $$ = []Expr{$1}
  444. }
  445. | exprlist ',' expr
  446. {
  447. $$ = append($1, $3)
  448. }
  449. osemi:
  450. | ';'
  451. ocomma:
  452. | ','
  453. %%
  454. // Compile compiles a Hawk program (name) from src. It is not safe
  455. // for concurrent use.
  456. func Compile(name string, src io.Reader) (*Program, error) {
  457. progName = name
  458. sc := new(scan.Scanner)
  459. ast = NewProgram(sc)
  460. lexlineno = 1
  461. nlsemi = false
  462. l := &yyLex{reader: bufio.NewReader(src)}
  463. yyParse(l)
  464. analyse(ast, sc)
  465. return ast, l.err
  466. }