org.goko.core.gcode.rs274ngcv3.parser.GCodeLexer.java Source code

Java tutorial

Introduction

Here is the source code for org.goko.core.gcode.rs274ngcv3.parser.GCodeLexer.java

Source

/*******************************************************************************
 *    This file is part of Goko.
 *
 *   Goko is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   Goko is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with Goko.  If not, see <http://www.gnu.org/licenses/>.
 *******************************************************************************/
package org.goko.core.gcode.rs274ngcv3.parser;

import java.io.InputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.goko.core.common.exception.GkException;
import org.goko.core.common.exception.GkFunctionalException;
import org.goko.core.common.i18n.MessageResource;
import org.goko.core.common.utils.Location;
import org.goko.core.gcode.element.validation.IValidationElement.ValidationSeverity;
import org.goko.core.gcode.element.validation.IValidationTarget;
import org.goko.core.gcode.element.validation.ValidationElement;

/**
 * GCode file tokenizer
 * @author PsyKo
 *
 */
public class GCodeLexer {
    /** Multi line comment pattern */
    private Pattern multilineCommentPattern;
    /** Simple comment pattern*/
    private Pattern simpleCommentPattern;
    /** Line number pattern */
    private Pattern lineNumberPattern;
    /** Word pattern*/
    private Pattern wordPattern;
    /** White space detection pattern at the beginning*/
    private Pattern spacePattern;
    /** Percent sign detection pattern at the beginning*/
    private Pattern percentPattern;

    /**
     * Constructor
     */
    public GCodeLexer() {
        multilineCommentPattern = Pattern.compile(GCodeTokenType.MULTILINE_COMMENT.getPattern(),
                Pattern.MULTILINE | Pattern.DOTALL);
        simpleCommentPattern = Pattern.compile(GCodeTokenType.SIMPLE_COMMENT.getPattern());
        lineNumberPattern = Pattern.compile(GCodeTokenType.LINE_NUMBER.getPattern());
        wordPattern = Pattern.compile(GCodeTokenType.WORD.getPattern());
        spacePattern = Pattern.compile("^[ ]+");
        percentPattern = Pattern.compile(GCodeTokenType.PERCENT.getPattern());
    }

    /**
     * Create a list of token from a String
     * @param stringCommand the string to extract tokens from
     * @return a list of {@link GCodeToken}
     * @throws GkException GkException
     */
    public List<GCodeToken> tokenize(String stringCommand, IValidationTarget validationTarget, int lineNumber)
            throws GkException {
        List<GCodeToken> lstTokens = new ArrayList<GCodeToken>();
        return createTokens(stringCommand, lstTokens, validationTarget, lineNumber, 0);
    }

    /**
     * Create a list of token from an InputStream
     * @param inStream the input stream
     * @return a list of {@link GCodeToken}
     * @throws GkException GkException
     */
    public List<List<GCodeToken>> tokenize(InputStream inStream, IValidationTarget validationTarget)
            throws GkException {
        Scanner scanner = new Scanner(inStream);

        List<List<GCodeToken>> lstFileTokens = new ArrayList<List<GCodeToken>>();
        String line = null;

        List<GCodeToken> tokens = null;
        int lineNumber = 0;
        while (scanner.hasNextLine()) {
            line = scanner.nextLine();
            tokens = tokenize(line, validationTarget, lineNumber);
            lineNumber++;
            lstFileTokens.add(tokens);
        }

        scanner.close();
        return lstFileTokens;
    }

    /**
     * Recursive method used to split the stringCommand into a list of tokens
     * @param stringCommand the string command
     * @param tokens the list of token
     * @throws GkException GkException
     */
    protected List<GCodeToken> createTokens(String pStringCommand, List<GCodeToken> tokens,
            IValidationTarget validationTarget, int lineNumber, int columnNumber) throws GkException {
        String stringCommand = pStringCommand;
        int totalColumn = columnNumber + StringUtils.length(stringCommand);
        if (StringUtils.isBlank(stringCommand)) {
            return tokens;
        }
        Matcher spaceMatcher = spacePattern.matcher(stringCommand);
        if (spaceMatcher.find()) {
            String remainingString = spaceMatcher.replaceFirst(StringUtils.EMPTY);
            return createTokens(remainingString, tokens, validationTarget, lineNumber,
                    totalColumn - StringUtils.length(remainingString));
        }
        Matcher multilineCommentMatcher = multilineCommentPattern.matcher(stringCommand);
        if (multilineCommentMatcher.find()) {
            String remainingString = extractToken(multilineCommentMatcher, tokens,
                    GCodeTokenType.MULTILINE_COMMENT);
            return createTokens(remainingString, tokens, validationTarget, lineNumber,
                    totalColumn - StringUtils.length(remainingString));
        }
        Matcher simpleCommentMatcher = simpleCommentPattern.matcher(stringCommand);
        if (simpleCommentMatcher.find()) {
            String remainingString = extractToken(simpleCommentMatcher, tokens, GCodeTokenType.SIMPLE_COMMENT);
            return createTokens(remainingString, tokens, validationTarget, lineNumber,
                    totalColumn - StringUtils.length(remainingString));
        }
        // Remove all white spaces ( comments already removed )
        while (StringUtils.startsWith(stringCommand, " ")) {
            stringCommand = stringCommand.replaceFirst("\\s", StringUtils.EMPTY);
            columnNumber += 1;
        }
        Matcher lineNumberMatcher = lineNumberPattern.matcher(stringCommand);
        if (lineNumberMatcher.find()) {
            String remainingString = extractToken(lineNumberMatcher, tokens, GCodeTokenType.LINE_NUMBER);
            return createTokens(remainingString, tokens, validationTarget, lineNumber,
                    totalColumn - StringUtils.length(remainingString));
        }

        Matcher wordMatcher = wordPattern.matcher(stringCommand);
        if (wordMatcher.find()) {
            String remainingString = extractToken(wordMatcher, tokens, GCodeTokenType.WORD);
            return createTokens(remainingString, tokens, validationTarget, lineNumber,
                    totalColumn - StringUtils.length(remainingString));
        }

        Matcher percentMatcher = percentPattern.matcher(stringCommand);
        if (percentMatcher.find()) {
            String remainingString = extractToken(percentMatcher, tokens, GCodeTokenType.PERCENT);
            return createTokens(remainingString, tokens, validationTarget, lineNumber,
                    totalColumn - StringUtils.length(remainingString));
        }
        if (validationTarget != null) {
            ValidationElement vElement = new ValidationElement(ValidationSeverity.ERROR,
                    new Location(lineNumber, columnNumber), StringUtils.length(stringCommand),
                    MessageFormat.format(MessageResource.getMessage("GCO-101"), stringCommand));
            validationTarget.addValidationElement(vElement);
            return tokens;
        } else {
            throw new GkFunctionalException("GCO-101", stringCommand);
        }
    }

    /**
     * Extract the first token from the given matcher
     * @param matcher the matcher
     * @param tokens the list of tokens
     * @param type the type of token to create
     * @return the remaining String after the token extraction
     */
    protected String extractToken(Matcher matcher, List<GCodeToken> tokens, GCodeTokenType type) {
        tokens.add(new GCodeToken(type, matcher.group()));
        return matcher.replaceFirst(StringUtils.EMPTY);
    }
}