docs: @Override
    public MtasTokenCollection createTokenCollection(Reader reader)
        throws MtasParserException, MtasConfigException {
      tokenCollection = new MtasTokenCollection();
      MtasTokenIdFactory mtasTokenIdFactory = new MtasTokenIdFactory();
      List<Level> levels = new ArrayList<>();
  //    Map<String,MtasToken> referencesNode = new HashMap<>();
  //    Map<String,List<MtasToken>> referencesNullElement = new HashMap<>();
      try {
        MtasPennTreebankReader treebankReader = new MtasPennTreebankReader(
            reader);
        // variables main administration
        int event = treebankReader.getEventType();
        int position = 0;
        boolean ignore = false;
        Level level = null;
        // variables for code
        List<Integer> codePositions = new ArrayList<>();
        Integer codeOffsetStart = null;
        Integer codeOffsetEnd = null;
        // variables for string
        String stringValue = null;
        int stringOffsetStart;
        int stringOffsetEnd;
        // loop
        while (true) {
          switch (event) {
          case MtasPennTreebankReader.EVENT_STARTBRACKET:
            if (level != null && level.code) {
              throw new MtasParserException(
                  "unexpected start bracket for " + NODE_CODE);
            } else {
              level = new Level();
              level.ignore = ignore;
              level.realOffsetStart = treebankReader.getPosition() + 1;
              levels.add(level);
            }
            break;
          case MtasPennTreebankReader.EVENT_ENDBRACKET:
            Objects.requireNonNull(level, "no level while ending bracket");
            level.realOffsetEnd = treebankReader.getPosition() - 1;
            Level parentLevel = levels.size() > 1 ? levels.get(levels.size() - 2)
                : null;
            createNodeMappings(mtasTokenIdFactory, level, parentLevel);
            // remove level
            if (parentLevel != null) {
              if (level.positionStart != null && level.positionEnd != null) {
                parentLevel.addPositionRange(level.positionStart,
                    level.positionEnd);
              }
              parentLevel.offsetStart = parentLevel.offsetStart == null
                  ? level.offsetStart : parentLevel.offsetStart;
              parentLevel.offsetEnd = level.offsetEnd == null
                  ? parentLevel.offsetEnd : level.offsetEnd;
              levels.remove(levels.size() - 1);
              level = parentLevel;
              ignore = level.ignore;
            } else {
              levels.clear();
              level = null;
              ignore = false;
  //            referencesNode.clear();
  //            referencesNullElement.clear();
            }
            break;
          case MtasPennTreebankReader.EVENT_NODE:
            Objects.requireNonNull(level, "no level while handling node");
            // register node with level
            level.node = treebankReader.getString();
            if (ignoreNodes.contains(level.node)) {
              ignore = true;
              level.ignore = true;
            }
            if (level.node.equals(NODE_CODE)) {
              level.code = true;
              if (!treebankReader.next() || (event = treebankReader
                  .getEventType()) != MtasPennTreebankReader.EVENT_STRING) {
                throw new MtasParserException("expected string for " + NODE_CODE);
              } else if (!level.ignore) {
                stringValue = treebankReader.getString();
                stringOffsetStart = treebankReader.getPosition();
                stringOffsetEnd = stringOffsetStart + stringValue.length();              
                if (!codePositions.isEmpty()) {
                  createCodeMappings(mtasTokenIdFactory, level, stringValue,
                      codeOffsetStart, codeOffsetEnd, stringOffsetStart,
                      stringOffsetEnd, codePositions);
                } else {
                  log.error("CODE without codePositions for "+stringValue);                
                }
                codePositions.clear();
                codeOffsetStart = null;
                codeOffsetEnd = null;
              }
            }
            break;
          case MtasPennTreebankReader.EVENT_STRING:
            Objects.requireNonNull(level, "no level while handling string");
            if (level.code) {
              throw new MtasParserException("unexpected string for " + NODE_CODE);
            } else if (!level.ignore) {
              stringValue = treebankReader.getString();
              stringOffsetStart = treebankReader.getPosition();
              stringOffsetEnd = stringOffsetStart + stringValue.length();
              if(level.offsetStart == null) {
                level.offsetStart = stringOffsetStart;
              }
              level.offsetEnd = stringOffsetEnd;
              if (stringValue.startsWith(NODE_CODE_PREFIX)) {
                codePositions.add(position);
                stringValue = stringValue.substring(NODE_CODE_PREFIX.length(),
                    stringValue.length());
                if(codeOffsetStart == null) {
                  codeOffsetStart = stringOffsetStart;
                }
                codeOffsetEnd = stringOffsetEnd;
              }
              // register position
              level.addPosition(position);
              // create mappings
              createStringMappings(mtasTokenIdFactory, level, stringValue,
                  stringOffsetStart, stringOffsetEnd, position);
              // increase position
              position++;
            }
            break;
          default:
            break;
          }
          if (!treebankReader.next()) {
            break;
          } else {
            event = treebankReader.getEventType();
          }
        }
      } catch (IOException e) {
        log.debug(e);
        throw new MtasParserException(
            "No valid Penn Treebank syntax: " + e.getMessage());
      }
      // final check
      tokenCollection.check(autorepair, makeunique);
      return tokenCollection;
  
    }