-
Notifications
You must be signed in to change notification settings - Fork 6
/
roll.peg
513 lines (414 loc) · 24.1 KB
/
roll.peg
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
// Copyright 2022 fy <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
{
//nolint:unreachable
package dicescript
{{ if not .grammarOnly }}
type ParserCustomData struct {
ParserData
}
func toStr(x []byte) string {
return string(x)
}
func stringsJoin(items any) string {
var buf bytes.Buffer
for _, i := range items.([]any) {
buf.Write(i.([]byte))
}
return buf.String()
}
{{ end }}
}
// 出口
dicescript <- sp stmtSt sp {
c.data.AddOp(typeHalt)
}
stmtSt <- "^st" st_expr
/ stmtRoot
stmtRoot <- stmtLines sp
stmtLines <- &{return !c.data.Config.DisableStmts} stmtWithBlock stmtLines?
/ flagsSwitch stmtLines?
/ comment sp stmtLines?
/ stmtWithSemicolon nextLine?
/ (';' sp)+ stmtLines?
flagsSwitch <- "//" sp "#EnableDice" sp1x id:identifier sp1x on:<("true" / "false")> commentLineRest {
onVal := on == "true"
switch id.(string) {
case "wod":
c.data.Config.EnableDiceWoD = onVal
case "coc":
c.data.Config.EnableDiceCoC = onVal
case "fate":
c.data.Config.EnableDiceFate = onVal
case "doublecross":
c.data.Config.EnableDiceDoubleCross = onVal
}
}
stmtWithSemicolon <- stmtBreak / stmtContinue / exprRoot
stmtWithBlock <- stmtIf / stmtFunc / stmtWhile / stmtReturn
nextLine <- ((spNoCR '\n' / sp ';') sp)+ stmtLines?
stmtBreak <- "break" sp {
if c.data.loopLayer == 0 {
p.addErr(errors.New("`break` is not allowed outside loop."))
return false
} else {
c.data.BreakPush()
}
}
stmtContinue <- "continue" sp {
if c.data.loopLayer == 0 {
p.addErr(errors.New("`continue` is not allowed outside loop."))
return false
} else {
c.data.ContinuePush()
}
}
stmtReturn <- "return" sp1x exprRoot { c.data.AddOp(typeReturn); }
/ "return" sp { c.data.PushNull(); c.data.AddOp(typeReturn); }
stmtWhile <- "while" sp1x { c.data.AddOp(typeBlockPush); c.data.LoopBegin(); c.data.OffsetPush() } exprRoot sp { c.data.AddOp(typeJne); c.data.OffsetPush() }
block { c.data.AddOp(typeJmp); c.data.OffsetPush(); c.data.OffsetJmpSetX(0, 2, true); c.data.OffsetJmpSetX(1, 1, false); c.data.ContinueSet(2); c.data.BreakSet(); c.data.OffsetPopN(3);c.data.LoopEnd(); c.data.AddOp(typeBlockPop) }
// push xxx // 这里是while后面的exprRoot
// jne 1
// ...
// jmp -3 // 跳回开始点
block <- ( '{' sp '}' / '{' sp stmtRoot '}' ) sp
stmtElse <- "else" (sp block / sp1x stmtIf)
stmtIf <- "if" sp1x (exprRoot sp { c.data.AddOp(typeBlockPush); c.data.AddOp(typeJne); c.data.OffsetPush() } block { c.data.AddOp(typeJmp); c.data.OffsetPopAndSet(); c.data.OffsetPush(); }
stmtElse? { c.data.OffsetPopAndSet(); c.data.AddOp(typeBlockPop) } / &{ p.addErr(errors.New("不符合if语法: if expr {...} [else {...}]")); return false; })
// 'if' exprRoot block
// ('else' block)?
// if ... then .. else
// push 1
// jne 2
// push "ret1"
// jmp 1
// push "ret2"
// 函数定义
func_def_params <- '(' sp ')' sp { c.data.CounterPush() }
/ '(' sp { c.data.CounterPush(); c.data.CounterAdd(1) } id:identifier sp { c.data.NamePush(id.(string)) } (',' sp id2:identifier sp { c.data.NamePush(id2.(string)) } {c.data.CounterAdd(1)} )* ')' sp
stmtFunc <- "func" sp1x id:identifier sp { c.data.NamePush(id.(string)) } func_def_params '{' sp { c.data.CodePush(p.pt.offset) } exprText:< stmtRoot? > '}' sp
{ num := c.data.CounterPop(); arr := []string{}; for i:=IntType(0); i<num; i++ { arr = append(arr, c.data.NamePop()) }; c.data.AddStoreFunction(c.data.NamePop(), arr, exprText.(string)) }
// 赋值
stmtAssignType1 <- id:identifier sp { c.data.NamePush(id.(string)) } '=' sp exprRoot { c.data.AddStore(c.data.NamePop()) }
stmtAssignType2 <- '&' id:identifier sp { c.data.NamePush(id.(string)) } '=' sp { c.data.CodePush(p.pt.offset) } expr:<exprRoot> { c.data.AddStoreComputed(c.data.NamePop(), expr.(string)) }
stmtAssignType3 <- '&' id:identifier sp { c.data.NamePush(id.(string)) } '.' id2:identifier sp { c.data.NamePush(id2.(string)) } sp '=' sp exprRoot { attr, objName := c.data.NamePop(), c.data.NamePop(); c.data.AddAttrSet(objName, attr, true) }
stmtAssignType4 <- "this" sp '.' sp id:identifier sp { c.data.NamePush(id.(string)) } '=' sp exprRoot { c.data.AddStoreLocal(c.data.NamePop()) }
stmtAssignType5 <- id:identifier sp { c.data.NamePush(id.(string)) } '.' sp id2:identifier sp { c.data.NamePush(id2.(string)) } '=' sp exprRoot { attr, objName := c.data.NamePop(), c.data.NamePop(); c.data.AddAttrSet(objName, attr, false) }
stmtAssignType6 <- exprSlice '[' sp exprRoot ']' sp '=' sp exprRoot { c.data.AddOp(typeItemSet) }
stmtAssignType7 <- exprSlice _sliceSuffix '=' sp exprRoot { c.data.AddOp(typeSliceSet) }
stmtAssign <- &stmtAssignType1 stmtAssignType1
/ &stmtAssignType2 stmtAssignType2
/ &stmtAssignType3 stmtAssignType3
/ &stmtAssignType4 stmtAssignType4
/* / 'global' '.' identifier sp { c.data.NamePush(text) } '=' sp exprRoot { c.data.AddStoreGlobal(c.data.NamePop()) }
注: attr_set 其实应该和 item_set 保持一致,只是暂时要求必须 identifier 开头 */
/ &stmtAssignType5 stmtAssignType5
/ &stmtAssignType6 stmtAssignType6
/ &stmtAssignType7 stmtAssignType7
// exprRoot <- exprSlice sp
// 注: 这个优化还是比较关键的,能节省大量回溯,但是开启memoized后我说不准
nestedBoost <- &(subX sp [-+*/%^dDcCaA&|?<>=]) (stmtAssign / exprSlice) / &subX subX
exprRoot <- nestedBoost / stmtAssign / exprSlice
_step <- (':' sp (exprRoot / sp { c.data.PushNull() }) / sp { c.data.PushNull() })
_sliceSuffix <- '[' sp (exprRoot / sp { c.data.PushNull() }) ':' sp (exprRoot / sp { c.data.PushNull() }) _step sp ']' sp
exprSliceType1 <- exprTernary _sliceSuffix (!'=') { c.data.AddOp(typeSliceGet) }
exprSlice <- &exprSliceType1 exprSliceType1
/ exprTernary
// 三元算符 ? :
exprValueIfExists <- exprLogicOr sp '?' sp { c.data.AddOp(typeJne); c.data.OffsetPush() } exprLogicOr sp { c.data.AddOp(typeJmp); c.data.OffsetPopAndSet(); c.data.OffsetPush(); } // 这里的Pop对应的是jne,所有jmp将攒到最后
exprTernaryType1 <- exprLogicOr sp '?' sp { c.data.AddOp(typeJne); c.data.OffsetPush() } exprLogicOr sp ':' sp { c.data.AddOp(typeJmp); c.data.OffsetPopAndSet(); c.data.OffsetPush() } exprLogicOr sp { c.data.OffsetPopAndSet() }
exprTernaryType2 <- exprValueIfExists { c.data.CounterPush() } ( ',' sp exprValueIfExists {c.data.CounterAdd(1)} )* { c.data.PushStr(""); limit:=c.data.CounterPop()+1; for i:=IntType(0); i<limit; i++ { c.data.OffsetPopAndSet() } }
exprTernary <- &exprTernaryType1 exprTernaryType1
/ &exprTernaryType2 exprTernaryType2
/ exprLogicOr
// switch { case 1: ..., case 2: ... }
// push cond1
// jne 2
// push "ret1"
// jmp 5
// push cond2
// jne 2
// push "ret2"
// jmp 1
// push 0 // 默认
// push "ret3"
// 注: 越靠下的算符优先级越高
// 逻辑运算
exprLogicOr <- exprLogicAnd (sp logicOr {c.data.AddOp(typeJeDup); c.data.OffsetPush()} exprLogicAnd { c.data.AddOp(typeJeDup); c.data.OffsetPush()} { c.data.AddOp(typePushLast); c.data.OffsetPopAndSet(); c.data.OffsetPopAndSet(); } )*
exprLogicAnd <- exprBitwiseOr (sp logicAnd exprBitwiseOr { c.data.AddOp(typeLogicAnd) } )*
// 位运算
exprBitwiseOr <- &{return c.data.Config.DisableBitwiseOp} exprCompare // 如果禁止,那么直接向下
/ exprBitwiseAnd (sp bitwiseOr exprBitwiseAnd { c.data.AddOp(typeBitwiseOr) })*
exprBitwiseAnd <- exprCompare (sp bitwiseAnd exprCompare { c.data.AddOp(typeBitwiseAnd) })*
// 比较
exprCompare <- exprAdditive (sp (
lt exprAdditive { c.data.AddOp(typeCompLT) }
/ le exprAdditive { c.data.AddOp(typeCompLE) }
/ eq exprAdditive { c.data.AddOp(typeCompEQ) }
/ ne exprAdditive { c.data.AddOp(typeCompNE) }
/ ge exprAdditive { c.data.AddOp(typeCompGE) }
/ gt exprAdditive { c.data.AddOp(typeCompGT) }
))*
// 加减
exprAdditive <- exprMultiplicative (sp (
add exprMultiplicative { c.data.AddOp(typeAdd) }
/ minus exprMultiplicative { c.data.AddOp(typeSubtract) }
))*
// 乘除余
exprMultiplicative <- exprNullCoalescing (sp (
multiply exprExp { c.data.AddOp(typeMultiply) }
/ divide exprExp { c.data.AddOp(typeDivide) }
/ modulus exprExp { c.data.AddOp(typeModulus) }
))*
// 空值合并
exprNullCoalescing <- exprExp (
sp nullCoalescing exprExp { c.data.AddOp(typeNullCoalescing) }
)*
// 平方
exprExp <- exprUnaryNeg (
sp exponentiation exprUnaryNeg { c.data.AddOp(typeExponentiation) }
)*
// 正数 负数
exprUnaryNeg <- minus exprDice { c.data.AddOp(typeNegation) }
/ exprUnaryPos
exprUnaryPos <- add exprDice { c.data.AddOp(typePositive) }
/ exprDice
// 骰子算符
nos <- (number / sub)
detailStart <- { c.data.CounterPush(); c.data.CounterAdd(IntType(p.pt.offset)); }
detailEnd <- { c.data.AddDiceDetail(c.data.CounterPop(), IntType(p.pt.offset)); }
_diceMod <- ("kl" / [qQ]) nos { c.data.AddOp(typeDiceSetKeepLowNum); } // 这里fvtt只有kl
/ ("kl" / [qQ]) { c.data.PushIntNumber("1"); c.data.AddOp(typeDiceSetKeepLowNum); }
/ ("kh" / [kK]) nos { c.data.AddOp(typeDiceSetKeepHighNum); } // 这里fvtt与国内骰一致
/ ("kh" / [kK]) { c.data.PushIntNumber("1"); c.data.AddOp(typeDiceSetKeepHighNum); }
/ ("dh") nos { c.data.AddOp(typeDiceSetDropHighNum); } // drop highest,需要在下一个之前,因为有2d20d1语法
/ ("dh") { c.data.PushIntNumber("1"); c.data.AddOp(typeDiceSetDropHighNum); } // 注:此处括号不影响生成的语法
/ ("dl") nos { c.data.AddOp(typeDiceSetDropLowNum); } // drop lowest, 这里故意去掉了3d20d1 的支持,需要写成3d20dl1
/ ("dl") { c.data.PushIntNumber("1"); c.data.AddOp(typeDiceSetDropLowNum); }
_diceModType2 <- "min" nos { c.data.AddOp(typeDiceSetMin) }
/ "max" nos { c.data.AddOp(typeDiceSetMax) }
_dicePearMod <- ("优势"/"優勢") { c.data.PushIntNumber("2"); c.data.AddOp(typeDiceSetTimes); c.data.PushIntNumber("1"); c.data.AddOp(typeDiceSetKeepHighNum); }
/ ("劣势"/"劣勢") { c.data.PushIntNumber("2"); c.data.AddOp(typeDiceSetTimes); c.data.PushIntNumber("1"); c.data.AddOp(typeDiceSetKeepLowNum); }
// 3d20, 3d20d2, 2d20优势
_diceType1 <- nos [dD] nos
// d20
_diceType2 <- [dD] nos
// 3d
_diceType3 <- nos [dD]
// d / d优势 / d劣势
_diceType4 <- [dD] ("优势" / "優勢" / "劣势" / "劣勢" / !xidStart)
// XdY/dY/Xd 中的 dy + 后缀部分,跟上面 _diceTypeX 一一对应
_diceExpr1 <- [dD] { c.data.AddOp(typeDiceInit); c.data.AddOp(typeDiceSetTimes); } nos _diceMod? _diceModType2?
_diceExpr2 <- [dD] { c.data.AddOp(typeDiceInit); } nos (_dicePearMod / _diceMod)? _diceModType2? // 注: 这一条是 dY 而不是 xdY
_diceExpr3 <- [dD] { c.data.AddOp(typeDiceInit); c.data.AddOp(typeDiceSetTimes); } _diceMod? _diceModType2?
_diceExpr4 <- [dD] { c.data.AddOp(typeDiceInit); c.data.AddOp(typeDiceSetTimes); } (_dicePearMod / _diceMod)? _diceModType2?
// 多重式子 d4d6d8
_diceExprX <- &_diceType2 detailStart _diceExpr1 detailEnd { c.data.AddOp(typeDice) }
// WOD规则,左侧个数,a加骰线,m面数,k阈值
// 这里有点麻烦,此处 a5c 将被视为变量,而 2a5c 被视为 2a5余c
_wodTypeMain <- [aA] nos (([mM] nos) / ([kK] nos) / ([qQ] nos))*
_wodDiceType <- nos _wodTypeMain / _wodTypeMain !xidContinue
_wodMain <- [aA] nos (([mM] nos { c.data.AddOp(typeWodSetPoints) }) / ([kK] nos { c.data.AddOp(typeWodSetThreshold) }) / ([qQ] nos { c.data.AddOp(typeWodSetThresholdQ) }))*
// COC规则,b奖励骰,p惩罚骰
_cocDiceType <- [pPbB] (nos !xidContinue / !xidContinue)
_diceCocBonus <- [bB] (nos !xidContinue / !xidContinue {c.data.PushIntNumber("1")}) detailEnd { c.data.AddOp(typeDiceCocBonus) }
_diceCocPenalty <- [pP] (nos !xidContinue / !xidContinue {c.data.PushIntNumber("1")}) detailEnd { c.data.AddOp(typeDiceCocPenalty) }
// 双十字规则
_dcDiceType <- nos [cC] nos ([mM] nos)*
// Fate规则
_fateDiceType <- [fF] !xidContinue
exprDice <- &_diceType1 detailStart nos _diceExpr1 detailEnd { c.data.AddOp(typeDice); } _diceExprX*
/ &_diceType2 detailStart _diceExpr2 detailEnd { c.data.AddOp(typeDice) } _diceExprX*
/ &{return !c.data.Config.DisableNDice} &_diceType3 detailStart nos _diceExpr3 detailEnd { c.data.AddOp(typePushDefaultExpr); c.data.AddOp(typeDice) } _diceExprX*
/ &{return !c.data.Config.DisableNDice} &_diceType4 detailStart { c.data.PushIntNumber("1") } _diceExpr4 detailEnd { c.data.AddOp(typePushDefaultExpr); c.data.AddOp(typeDice) } _diceExprX*
/ &{return c.data.Config.EnableDiceCoC} &_cocDiceType detailStart (_diceCocBonus / _diceCocPenalty)
/ &{return c.data.Config.EnableDiceWoD} &_wodDiceType detailStart { c.data.AddOp(typeWodSetInit) } (nos { c.data.AddOp(typeWodSetPool) } _wodMain / _wodMain !xidContinue) detailEnd { c.data.AddOp(typeDiceWod) }
/ &{return c.data.Config.EnableDiceDoubleCross} &_dcDiceType detailStart { c.data.AddOp(typeDCSetInit) } nos { c.data.AddOp(typeDCSetPool) } [cC] nos (([mM] nos { c.data.AddOp(typeDCSetPoints) }) )* detailEnd { c.data.AddOp(typeDiceDC) }
/ &{return c.data.Config.EnableDiceFate} &_fateDiceType detailStart [fF] !xidContinue detailEnd { c.data.AddOp(typeDiceFate) }
/ value
array_call <- "kh" { c.data.WriteCode(typeAttrGet, string("kh")) } (number { c.data.AddInvoke(1) } / {c.data.AddInvoke(0)})
/ "kl" { c.data.WriteCode(typeAttrGet, string("kl")) } (number { c.data.AddInvoke(1) } / {c.data.AddInvoke(0)})
/ ('[' sp exprRoot sp ']' sp { c.data.AddOp(typeItemGet) })+
// TODO: value 中的 item_get attr_get 连写这种形式处理的很烂,之后改掉
// 注: 这样套一层先做检查的原因是,在这种赋值语句中a['x'] = 1,左值是一个合法的value语句,到出现等号才能真正确认是赋值语句
item_getX <- ('[' sp exprRoot sp ']' sp (!'=') { c.data.AddOp(typeItemGet); } func_invoke? )*
item_get <- (&&(item_getX) item_getX)?
attr_getX <- ('.' (sp id:identifier sp { c.data.WriteCode(typeAttrGet, id.(string)) }) func_invoke? )*
attr_get <- (&&attr_getX attr_getX)?
func_invoke <- '(' sp ')' { c.data.AddInvoke(0) }
/ '(' sp { c.data.CounterPush(); c.data.CounterAdd(1) } exprRoot sp (',' sp exprRoot {c.data.CounterAdd(1)} )* sp ')' { c.data.AddInvoke(c.data.CounterPop()) }
dict_item <- ((value_id_without_colon / exprRoot) sp ':' sp exprRoot) sp { c.data.CounterAdd(1) }
// 右值
value_id_without_colon <- id:identifierWithoutColon sp { c.data.WriteCode(typeLoadName, string(id.(string))) } func_invoke? item_get attr_get
value_array_range <- '[' sp exprRoot ".." sp exprRoot ']' sp { c.data.AddOp(typePushRange) }
value_array <- '[' sp { c.data.CounterPush(); c.data.CounterAdd(1) } exprRoot (',' sp exprRoot {c.data.CounterAdd(1)} )* ']' sp { c.data.PushArray(c.data.CounterPop()) }
value <- "true" sp { c.data.PushIntNumber("1"); }
/ "false" sp { c.data.PushIntNumber("0"); }
/ "null" sp { c.data.PushNull() }
/ "this" sp { c.data.PushThis() } item_get attr_get
/ '&' id:identifier sp { c.data.WriteCode(typeLoadNameRaw, id.(string)); } attr_get
/ float
/ number
// 变量
/ &(identifier spNoCR) detailStart id:identifier detailEnd spNoCR { c.data.WriteCode(typeLoadNameWithDetail, id.(string)); } func_invoke? item_get attr_get
/ fstring
/ sub item_get attr_get
/ '[' sp ']' sp { c.data.PushArray(0) } array_call? attr_get
/ &value_array_range value_array_range array_call? attr_get
/ &value_array value_array array_call? attr_get
/ '{' sp '}' sp { c.data.PushDict(0) } item_get attr_get
/ '{' sp { c.data.CounterPush() } dict_item (',' sp dict_item )* ','? '}' sp { c.data.PushDict(c.data.CounterPop()) } item_get attr_get
// 数字
number <- [0-9]+ { c.data.PushIntNumber(toStr(c.text)); }
float <- [0-9]* '.' [0-9]+ { c.data.PushFloatNumber(toStr(c.text)); }
// 字符串
strPart1 <- items:(strEscape / strPart1Normal)+ { c.data.PushStr(stringsJoin(items)); c.data.CounterAdd(1) }
strPart1Normal <- (&[^'\\].)+ { return c.text }
strPart2 <- items:(strEscape / strPart2Normal)+ { c.data.PushStr(stringsJoin(items)); c.data.CounterAdd(1) }
strPart2Normal <- (&[^"\\].)+ { return c.text }
strPart3 <- items:(strEscape / strPart3Normal)+ { c.data.PushStr(stringsJoin(items)); c.data.CounterAdd(1) }
strPart3Normal <- (&[^`\\{].)+ { return c.text }
strPart4 <- items:(strEscape / strPart4Normal)+ { c.data.PushStr(stringsJoin(items)); c.data.CounterAdd(1) }
strPart4Normal <- (&[^\x1e\\{].)+ { return c.text }
strEscape <- "\\n" { return []byte("\n") }
/ "\\r" { return []byte("\r") }
/ "\\f" { return []byte("\f") }
/ "\\t" { return []byte("\t") }
/ "\\\\" { return []byte("\\") }
/ "\\'" { return []byte("'") }
/ "\\\"" { return []byte("\"") }
/ "\\{" { return []byte("{") }
/ "\\}" { return []byte("}") }
/ '\\' { return []byte("\\") }
// fstringExpr1 <- exprRoot {c.data.CounterAdd(1)} / &{ p.addErr(errors.New("{} 内必须是一个表达式")); return false; }
// fstringExpr <- '{' sp fstringExpr1 sp ('}' / &{ p.addErr(errors.New("无法处理字符 " + string(p.pt.rn))); return false })
fstringStmt <- "{%" sp ({ c.data.AddOp(typeFStringBlockPush) } stmtRoot { c.data.AddOp(typeFStringBlockPop); c.data.CounterAdd(1) } / &{ p.addErr(errors.New("{% %} 内必须是语句块或表达式")); return false; }) sp "%}"
fstringStmt2 <- "{" sp ({ c.data.AddOp(typeFStringBlockPush) } stmtRoot { c.data.AddOp(typeFStringBlockPop); c.data.CounterAdd(1) } / &{ p.addErr(errors.New("{} 内必须是语句块或表达式")); return false; }) sp "}"
fstring <- (
('\'' '\'' { c.data.PushStr("") })
/ ('\x1e' '\x1e' { c.data.PushStr("") })
/ ('"' '"' { c.data.PushStr("") })
/ ('`' '`' { c.data.PushStr("") })
/ ('\'' { c.data.CounterPush() } strPart1* '\'' { c.data.CounterPop() } )
/ ('"' { c.data.CounterPush() } strPart2* '"' { c.data.CounterPop() })
/ ('`' { c.data.CounterPush() } ( strPart3 / fstringStmt / fstringStmt2 )* '`' { c.data.AddFormatString(c.data.CounterPop()) })
/ ('\x1e' { c.data.CounterPush() } ( strPart4 / fstringStmt / fstringStmt2 )* '\x1e' { c.data.AddFormatString(c.data.CounterPop()) }) // 特殊标记 0x1E
) sp
keywords <- "while" / "if" / "else" / "continue" / "break" / "return" / "func"
keywords_test "keywords" <- !(keywords !xidContinue &{ p.addErr(errors.New("使用关键字作为变量名")); return true})
identifier <- keywords_test xidStart (xidContinue / ':')* {
return toStr(c.text);
}
// 不含冒号的 identifier 用于字典,因为a:b是合法变量名,所以 {a:b} 会被误判
identifierWithoutColon <- keywords_test xidStart xidContinue* {
return toStr(c.text);
}
// L + Other_ID_Start
xidStart <- [_$\p{L}\p{Other_ID_Start}]
// xid_start + Nl + Mn + Mc + Nd + Pc + Other_ID_Continue \u200C\u200D
xidContinue <- [$\p{L}\p{Other_ID_Start}\p{Nl}\p{Mn}\p{Mc}\p{Nd}\p{Pc}\p{Other_ID_Continue}()【】]
// 括号
sub <- parenOpen exprRoot parenClose
subX <- sub item_get attr_get
parenOpen <- '(' sp
parenClose <- ')' sp
// 加减乘除余 乘方 空值合并
add <- ('+'/'+') sp
minus <- ('-' / '-') sp
multiply <- ('*' / '*') sp
divide <- ('/' / '/') sp
modulus <- '%' sp
exponentiation <- '^' sp / "**" sp
nullCoalescing <- "??" sp
// 按位算符
bitwiseOr <- '|' sp
bitwiseAnd <- '&' sp
// 逻辑算符
logicOr <- "||" sp
logicAnd <- "&&" sp
// 比较算符
// 注: 全角符号过于阴间,peg没办法处理==,因此放弃兼容了,可以读入前做一个统一替换
lt <- "<" sp
gt <- ">" sp
le <- "<=" sp
ge <- ">=" sp
eq <- "==" sp
ne <- "!=" sp
// 其他
sp "whitespace" <- [ \n\t\r]*
sp1 "whitespace" <- [ \n\t\r] sp / !.
sp1x <- sp1 sp
spNoCR <- [ \t]*
comment <- spNoCR "//" commentLineRest
commentLineRest <- (![\r\n] .)* ([\r\n] / !.)
commentLineRest2 <- (![\r\n] .)* [\r\n]
// --------------------------
// 改版后记: 我注意到字节码的形式对于st指令来说可能不是一个好的方式
// 借助新版的语义解析,我们可以为其生成类似语法树的玩意,这样可能更好一些
// 不过,先让旧的能跑起来再说
// st 力量60敏捷70
// st 力量60 敏捷70
// st 智力:80
// st 知识=90
// st 力量+1
// st 力量+1d4
// st 力量+1d4+2
// st 力量-1d4+2 => 力量 = 力量 - (1d4+2)
// st &手枪=1d6
// st &手枪=(1d6+2)
st_expr <- st_modify_multi_1
/ st_assign_multi
est <- ( &'(' exprRoot )
/ &exprRoot {
c.data.FlagsPush()
c.data.Config.DisableStmts = true
c.data.Config.DisableNDice = true
c.data.Config.DisableBitwiseOp = true
} exprRoot { c.data.FlagsPop() }
st_assign_multi <- (st_assign sp ','? sp)+
st_star <- '*' sp (float / number / sub)
st_assign <- &(st_name2 sp (':' / '=') sp est) st_name2 sp (':' / '=') sp est { c.data.AddStName() } // 射击:弓箭:40 / 射击:弓箭40
/ &(st_name1 est) st_name1 est { c.data.AddStName() } // 测试:力量60
/ &(st_name2r sp st_star sp (':' / '=') sp est) st_name2r sp st_star sp (':' / '=') sp est { c.data.AddOp(typeStX1) } // 属性2*2.0: 5
/ &(st_name2r sp '*' sp (':' / '=') sp est) st_name2r sp '*' sp (':' / '=') sp est { c.data.AddOp(typeStX0) } // 属性*: 4
/ &(st_name2r sp (':' / '=') sp est) st_name2r sp (':' / '=') sp est { c.data.AddStName() } // 属性2: 70
/ &(st_name1r est) st_name1r est { c.data.AddStName() } // 力量60
/ &('&' st_name2 sp (':' / '=') est) '&' st_name2 sp (':' / '=') sp { c.data.CodePush(p.pt.offset); } text:< est > { c.data.AddStoreComputedOnStack(text.(string)); c.data.AddStName() } // &手枪 = 1d4
/ &('&' st_name2r sp (':' / '=') est) '&' st_name2r sp (':' / '=') sp { c.data.CodePush(p.pt.offset); } text:< est > { c.data.AddStoreComputedOnStack(text.(string)); c.data.AddStName() } // &手枪 = 1d4
// 第一类:
// 力量+1d3
// 力量123+=1d3 // 这种语法已经不支持,原因忘记了
// '力量123'+=1d3
st_modify_multi_1 <- (st_modify_lead sp ','? sp) st_modify_multi_rest
st_modify_lead <- &(st_name2 st_modify_rest1) st_name2 st_modify_rest1
/ &(st_name2r st_modify_rest1) st_name2r st_modify_rest1
/ &(st_name1 st_modify_rest) st_name1 st_modify_rest
/ &(st_name1r st_modify_rest) st_name1r st_modify_rest
st_modify_multi_rest <- (st_modify_lead sp ','? sp)*
st_modify_rest1 <- sp (
"+=" sp text:< exprRoot > {c.data.AddStModify("+", text.(string))} /
"-=" sp text:< exprRoot > {c.data.AddStModify("-=", text.(string))}
)
st_modify_rest <- sp (
'+' '='? sp text:< exprRoot > {c.data.AddStModify("+", text.(string))} /
"-=" sp text:< exprRoot > {c.data.AddStModify("-=", text.(string))} /
&( '-' ) sp text:< exprRoot > {c.data.AddStModify("-", text.(string))} // 这一个式子是为了兼容st a-1-1视为a-2
)
st_name1 <- text:<( id_ch+ ":" id_ch+ )> { c.data.PushStr(text.(string)) } // 结尾不带数字
st_name1r <- text: <( id_ch+ )> { c.data.PushStr(text.(string)) } // 结尾不带数字
/ '\'' text:< (id_ch / [0-9] / ' ' / ':')+ > '\'' { c.data.PushStr(text.(string)) } // 任意字符,需要框起来
st_name2 <- st_name1 // 目前和1一样,占位符
st_name2r <- text:<( id_ch+ )> { c.data.PushStr(text.(string)) } // 结尾可带数字,即常规变量名
/ '\'' text:< (id_ch / [0-9] / ' ' / ':')+ > '\'' { c.data.PushStr(text.(string)) } // 任意字符
id_ch <- xidStart