All Downloads are FREE. Search and download functionalities are using the official Maven repository.

view.lib.Parser.js Maven / Gradle / Ivy

const OCCURENCE_TOKEN = '@>'

function ParseError (name, params) {
  this.name = name
  this.params = params
}

function Node (name, parent) {
  this.name = name
  this.parent = parent

  this.children = []

  if (this.parent) {
    this.parent.children.push(this)
  }
}

function Input () {
  this.root = new Node()
  this.vars = {} // key = var name ; value = node
  this.loops = []
  this.maxNestedLoop = 0
  this.statement = 'Auto-generated code below aims at helping you parse\nthe standard input according to the problem statement.'
  this.containsVarString = false

  this.getVarType = function (name) {
    return this.vars[name].parent.name
  }

  this.getVar = function (name) {
    return this.vars[name].parent
  }

  this.getVarComment = function (name) {
    return this.vars[name].comment
  }

  this.addVar = function (name, node) {
    this.vars[name] = node
    node.original = node.name
  }

  this.addLoop = function (node) {
    this.loops.push(node)
    node.original = node.param
  }

  this.setMaxNestedLoop = function (cntLoop) {
    if (this.maxNestedLoop < cntLoop) {
      this.maxNestedLoop = cntLoop
    }
  }

  this.hasStatement = function () {
    return this.statement != null && this.statement.trim().length > 0
  }

  this.hasString = function () {
    return this.containsVarString
  }
}

const Parser = function () {
  this.cursor = 0
  this.allowType = ['int', 'long', 'float', 'string', 'word']
}

Parser.prototype.getCodeName = function (from, name) {
  let occ = 0
  while (from[name + OCCURENCE_TOKEN + occ]) {
    occ++
  }
  return name + OCCURENCE_TOKEN + occ
}

Parser.prototype.getFirstCodeName = function (from, name) {
  return name + OCCURENCE_TOKEN + '0'
}

Parser.prototype.parse = function (cginput, turnBased) {
  try {
    this.write = []
    this.vars = {}
    this.code = cginput
    const input = new Input()
    input.turnBased = turnBased
    while (this.hasNext()) {
      this.parseTree(input.root, input, 0)
    }
    return input
  } finally {
    this.write = null
    this.code = null
    this.cursor = 0
  }
}

Parser.prototype.read = function (input, n) {
  const line = this.nextLine()
  const wholeRead = line.split(' ')

  for (let i = 0; i < wholeRead.length; i++) {
    const typeValue = wholeRead[i].split(':')
    const name = typeValue[0]
    const type = typeValue[1]
    if (!/^[a-zA-Z0-9]+$/.test(name)) {
      throw new ParseError('InvalidVariable', {
        variable: name
      })
    }
    if (!type) {
      throw new ParseError('MissingType', {
        variable: name
      })
    }
    const nType = new Node(type, n)
    if (/^string\([a-zA-Z0-9]+\)$/.test(type)) {
      nType.param = this.extractParam(nType.name)
      nType.name = 'string'
      input.containsVarString = true
    } else if (/^word\([a-zA-Z0-9]+\)$/.test(type)) {
      nType.param = this.extractParam(nType.name)
      nType.name = 'word'
    } else if (type === 'word' || type === 'string') {
      throw new ParseError('MissingLength', {
        variable: name,
        type: type
      })
    } else if (this.allowType.indexOf(type) < 0) {
      throw new ParseError('InvalidType', {
        variable: name,
        type: type
      })
    }

    const codeName = this.getCodeName(input.vars, name)
    input.addVar(codeName, new Node(name, nType))

    if (nType.name === this.STRING && (i > 0)) {
      throw new Error('InvalidStringRead')
    }
  }
}

Parser.prototype.parseTree = function (node, input, loopCnt) {
  if (!this.hasNext()) {
    return
  }

  const next = this.next().split(':')
  const cmd = next[0]
  const param = next[1]
  const parser = this

  if (typeof param !== 'undefined') {
    throw new ParseError('InvalidKeyword', {
      param: cmd + ':' + param
    })
  }

  switch (cmd) {
    case 'loop':
    {
      const n = new Node(cmd, node)
      n.param = this.next()
      input.addLoop(n)
      input.setMaxNestedLoop(++loopCnt)
      this.parseTree(n, input, loopCnt)
      break
    }
    case 'gameloop':
    {
      const n = new Node(cmd, node)
      while (this.hasNext()) {
        this.parseTree(n, input, loopCnt)
      }
      break
    }
    case 'read':
    {
      const n = new Node(cmd, node)
      this.read(input, n)
      break
    }
    case 'loopline':
    {
      const n = new Node(cmd, node)
      n.param = this.next()
      input.addLoop(n)
      input.setMaxNestedLoop(++loopCnt)
      const nRead = new Node('readline', n)
      this.read(input, nRead)

      break
    }
    case 'write':
      const write = new Node(cmd, node)
      this.write.push(write)

      let out = this.nextLine()

      let match = out.match(/join\(([^,)]+(?:,[^,)]+)*)\)\s*(?:\/\/\s*(.*))?/)
      if (match) {
        let params = match[1].split(',')
        const comment = match[2] || null
        let separator = ' '
        const separatorMatch = params[params.length - 1].match(/\s*sep\s*=\s*"(.*)"\s*/)
        if (separatorMatch) {
          params = params.slice(0, -1)
          separator = separatorMatch[1]
        }
        write.param = params.map(function (vari) {
          const name = vari.trim()
          match = name.match(/"(.*)"/)
          if (match) {
            return {type: 'CONST', value: match[1]}
          } else {
            const codeName = parser.getFirstCodeName(input.vars, name)
            return {type: 'VAR', node: input.getVar(codeName)}
          }
        })
        write.param.separator = separator
        write.comment = comment
      } else {
        const buff = [out]
        while (this.hasNext()) {
          out = this.nextLine()
          if (out.length === 0) {
            break
          }
          buff.push(out)
        }

        write.param = buff.join('\n')
      }
      break
    case 'INPUT':
      if (this.hasNext()) {
        this.nextLine()
      }
      while (this.hasNext()) {
        const line = this.nextLine()
        if (line.length === 0) {
          break
        } else {
          const splitPos = line.indexOf(':')
          const varName = line.substring(0, splitPos).trim()
          const comment = line.substring(splitPos + 1).trim()

          const codeName = this.getCodeName(this.vars, varName)
          this.vars[codeName] = true
          const varNode = input.vars[codeName]
          if (varNode) {
            varNode.comment = comment
          }
        }
      }
      break
    case 'OUTPUT':
      const buff = []
      if (this.hasNext()) {
        this.nextLine()
      }
      while (this.hasNext()) {
        const line = this.nextLine()
        if (line.length === 0) {
          break
        } else {
          buff.push(line)
        }
      }
      if (buff.length > 0) {
        this.write.forEach(function (write) {
          if (!write.comment) {
            write.comment = buff.join('\n')
          }
        })
      }
      break
    case 'STATEMENT':
    {
      const buff = []
      if (this.hasNext()) {
        this.nextLine()
      }
      while (this.hasNext()) {
        const line = this.nextLine()
        if (line.length === 0) {
          break
        } else {
          buff.push(line, '\n')
        }
      }
      if (buff.length > 0) {
        buff.pop() // remove the last \n
        input.statement = buff.join('')
      }
      break
    }
    default:
      throw new ParseError('InvalidKeyword', {
        param: cmd
      })
  }
}

Parser.prototype.next = function () {
  while (this.hasNext() && (this.code.charAt(this.cursor) === ' ' || this.code.charAt(this.cursor) === '\n')) {
    this.cursor++
  }

  const last = this.cursor
  while (this.hasNext() && this.code.charAt(this.cursor) !== ' ' && this.code.charAt(this.cursor) !== '\n') {
    this.cursor++
  }

  return this.code.substring(last, this.cursor).trim()
}

Parser.prototype.nextLine = function () {
  const last = this.cursor
  while (this.hasNext() && this.code.charAt(this.cursor) !== '\n') {
    this.cursor++
  }

  return this.code.substring(last, this.cursor++).trim()
}

Parser.prototype.hasNext = function () {
  return this.cursor < this.code.length
}

Parser.prototype.extractParam = function (type) {
  const iopen = type.indexOf('(')
  const iclose = type.indexOf(')')
  return type.substring(iopen + 1, iclose)
}

export default Parser




© 2015 - 2025 Weber Informatics LLC | Privacy Policy