Updated the grammar today. I realized I was trying to be too "generic" and ended up writing a kind of lazy grammar that is technically very extensible, but put too much work into the backend semantic parsing.

I rewrote the grammar to be much longer and restrictive, which allows me to also write the backend quicker (once I figure out how...).

The new grammar also supports multiple actors, which hilariously the sim only half-supports (it doesn't support multiple stacks of the same aura, nor does it support cross class buffs). Oh well. At least the future looks bright.

Irony's documentation sucks. I need to figure out how to overwrite the AST actions.

New grammar:

Code:
action
   action -> string 
actionBlock
   actionBlock -> precast 
   actionBlock -> gcd 
   actionBlock -> ogcd 
actionBlock+
   actionBlock+ -> actionBlock+ actionBlock 
   actionBlock+ -> actionBlock 
actionBlocks  (Nullable) 
   actionBlocks -> 
   actionBlocks -> actionBlock+ 
actions  (Nullable) 
   actions -> action 
   actions -> action , actions 
   actions -> 
actionStatement
   actionStatement -> ( conditionals ) { actions } 
   actionStatement -> comment 
actionStatement+
   actionStatement+ -> actionStatement+ actionStatement 
   actionStatement+ -> actionStatement 
actionStatements  (Nullable) 
   actionStatements -> 
   actionStatements -> actionStatement+ 
actionVar
   actionVar -> nextaction 
actorListStatement
   actorListStatement -> playersAdd 
   actorListStatement -> targetsAdd 
actorStatement
   actorStatement -> actor . actorVar = val 
actorVar
   actorVar -> class 
   actorVar -> attrVar 
   actorVar -> autoattack 
   actorVar -> auraVar 
   actorVar -> gcdVar 
   actorVar -> cdVar 
   actorVar -> actionVar 
attribute
   attribute -> str 
   attribute -> dex 
   attribute -> sks 
   attribute -> det 
   attribute -> chr 
attrVar
   attrVar -> attr . attribute 
auraVar
   auraVar -> aura . string . remaining 
   auraVar -> aura . string 
boolVar
   boolVar -> actor . actorVar 
   boolVar -> sim . simVar 
cdVar
   cdVar -> cd . string 
conditional
   conditional -> boolVar 
   conditional -> notBoolVar 
   conditional -> testVar 
conditionals  (Nullable) 
   conditionals -> conditional 
   conditionals -> conditional & conditionals 
   conditionals -> 
gcd
   gcd -> [ actor . GCD ] actionStatements 
gcdVar
   gcdVar -> lastgcd 
   gcdVar -> nextgcd 
notBoolVar
   notBoolVar -> ! boolVar 
ogcd
   ogcd -> [ actor . OGCD ] actionStatements 
playersAdd
   playersAdd -> *players+= actor 
precast
   precast -> [ actor . PRECAST ] actionStatements 
script
   script -> setup actionBlocks 
script'
   script' -> script EOF 
setup
   setup -> [SETUP] setupStatements 
setupStatement
   setupStatement -> actorStatement 
   setupStatement -> actorListStatement 
   setupStatement -> simStatement 
   setupStatement -> comment 
setupStatement+
   setupStatement+ -> setupStatement+ setupStatement 
   setupStatement+ -> setupStatement 
setupStatements  (Nullable) 
   setupStatements -> 
   setupStatements -> setupStatement+ 
simStatement
   simStatement -> sim . simVar = val 
simVar
   simVar -> duration 
   simVar -> execute 
   simVar -> diagnostic 
   simVar -> trials 
   simVar -> output 
targetsAdd
   targetsAdd -> *targets+= actor 
test
   test -> == 
   test -> != 
   test -> < 
   test -> <= 
   test -> > 
   test -> >= 
testVar
   testVar -> boolVar test val 
val
   val -> boolean 
   val -> number 
   val -> string 
   val -> stringLit
New sample script:

Code:
[SETUP]
#sets up an alias for our player
*players+=p1
#sets up an alias for our target
*targets+=t1

#load skills and traits
p1.class = drg

# setup attributes
# nonlisted attributes are assumed to be 0
p1.attr.str=500
p1.attr.dex=200
p1.attr.sks=400

# setup server variables
sim.duration=600
# execute is duration from end of sim
sim.execute=200

# setup diagnostic or no - diagnostic runs 1 run with log output, for testing your rotation
sim.diagnostic=true

# otherwise setup sim trials
sim.trials=10000

# i/o
sim.output="./output.txt"

[p1.PRECAST]
# place a sequential list of ogcd/gcd actions here
# any action that is offensive will begin the sim timer
# however, you may place as many actions as you like
# if you have a set opener rotation you wish to follow, enter it here
# and the [GCD] actionlists will follow once the action queue is complete
(){x_potion,blood_for_blood,heavy_thrust}

[p1.GCD]
# remaining is set to 0 if an aura does not exist
# you do not need to test for both exists and remaining
# if an action is in the queue, no further actions will be run
# if a condition is satisfied, the sim will attempt to cast the action
# if an action succeeds, no further actions will be run until the queue is empty
# the only supported boolean operator is &
# to do | actions, use multiple action lines
# blank conditionals are always true
(p1.aura.heavy_thrust.remaining<5.0){heavy_thrust}
(t1.aura.chaos_thrust.remaining<12.0){impulse_drive,disembowel,chaos_thrust}
(t1.aura.phlebotomize<5.0){phlebotomize}
(){true_thrust,vorpal_thrust,full_thrust}

[p1.OGCD]
# you'll need this unless you want to constantly clip GCDs
# actionlist execution stops as soon as a successful action is entered
# blank actions are automatically successful
(p1.nextgcd<1.0){}
(){blood_for_blood}
(p1.nextaction==full_thrust){life_surge}
(!p1.cd.jump){power_surge}
(){jump}
(){dragonfire_dive}
(){leg_sweep}