Skip to main content
Bounty Ended with 100 reputation awarded by caird coinheringaahin g
clarify 177 note
Source Link
tjjfvi
  • 7.4k
  • 22
  • 36

JavaScript (ES6), 177 bytes (LL1 rotated 177°)

177 looks like LL1 rotated 177°, so I stopped golfing.

JavaScript (ES6), 177 bytes (LL1 rotated 177°)

JavaScript (ES6), 177 bytes

177 looks like LL1 rotated 177°, so I stopped golfing.

remove asterisk disclaimer
Source Link
tjjfvi
  • 7.4k
  • 22
  • 36

JavaScript*JavaScript (ES6), 177 bytes (LL1 rotated 177°)

* This uses JS features likely introduced since the question's posting in 2015

JavaScript*, 177 bytes (LL1 rotated 177°)

* This uses JS features likely introduced since the question's posting in 2015

JavaScript (ES6), 177 bytes (LL1 rotated 177°)

Source Link
tjjfvi
  • 7.4k
  • 22
  • 36

JavaScript*, 177 bytes (LL1 rotated 177°)

s=>(f=(x,i)=>x<"A"||x>"Z"?v=s[i]==x&&[i+1,x]:s.split`
`.some((r,a,j)=>v=r[0]==x&&[j=i,a=[a],...r].slice(3).every(y=>f(y,j)&&a.push(([j]=v)[1]))&&[j,a]))("S",0)&&s[v[0]]==0&&v[1]

Try it online!

Outputs false if the string does not match, otherwise outputs a nested array of rule indices and terminals:

[2,"(",[1,[3,"a"]],"+",[3,"a"],")"]

Ungolfed

str =>
  (applyRule = (ruleName, index) =>
    ruleName < "A" || ruleName > "Z"
      ? result = str[index] == ruleName && [index + 1, ruleName]
      : str.split("\n").some(
        (rule, appliedRules, jndex) => result =
          rule[0] == ruleName &&
          (
            jndex = index,
            appliedRules = [appliedRules],
            [...rule].slice(1).every(char =>
              applyRule(char, jndex)
              && appliedRules.push(([jndex] = result)[1])
            )
            && [jndex, appliedRules]
          )
      )
  )("S", 0)
  && str[result[0]] == 0 // "\n" == 0
  && result[1]
function main(input) {
  const [str, ...rules] = input.split("\n")

  const result = applyRule("S", 0)

  if(result && result[0] === str.length)
    return result[1]

  function applyRule(ruleName, index) {
    if (ruleName === ruleName.toLowerCase())
      return str[index] === ruleName ? [index + 1, ruleName] : null

    main: for (const [ruleIndex, rule] of rules.entries()) {
      if (!rule.startsWith(ruleName))
        continue
      let curIndex = index
      let appliedRules = [ruleIndex + 1]
      for (const char of rule.slice(1)) {
        let result = applyRule(char, curIndex)
        if (!result) continue main
        curIndex = result[0]
        appliedRules.push(result[1])
      }
      return [curIndex, appliedRules]
    }

    return null
  }
}

* This uses JS features likely introduced since the question's posting in 2015