001/*-------------------------------------------------------------------------+
002|                                                                          |
003| Copyright (c) 2009-2018 CQSE GmbH                                        |
004|                                                                          |
005+-------------------------------------------------------------------------*/
006package eu.cqse.check.cpp;
007
008import java.util.regex.Pattern;
009
010/**
011 * Parser for C++ integer literals, see
012 * https://en.cppreference.com/w/cpp/language/integer_literal
013 */
014public class CppIntegerLiteralParser {
015
016        private static String DECIMAL_LITERAL_PATTERN = "[0-9']+";
017
018        private static String HEX_LITERAL_PATTERN = "0x[0-9a-f']+";
019
020        private static String OCTAL_LITERAL_PATTERN = "0[0-8']+";
021
022        private static String BINARY_LITERAL_PATTERN = "0b[01']+";
023
024        /** Suffix to indicate the type of the integer literal. */
025        private static String INTEGER_SUFFIX_PATTERN = "(u|l|ll|ul|ull|lu|llu)?";
026
027        /**
028         * String literals matching this pattern are valid integer literals.
029         */
030        private static Pattern INTEGER_LITERAL_PATTERN = Pattern
031                        .compile("(" + DECIMAL_LITERAL_PATTERN + "|" + HEX_LITERAL_PATTERN + "|" + OCTAL_LITERAL_PATTERN + "|"
032                                        + BINARY_LITERAL_PATTERN + ")" + INTEGER_SUFFIX_PATTERN, Pattern.CASE_INSENSITIVE);
033
034        /** Checks if the given string literal is a valid C++ integer literal. */
035        public static boolean isInteger(String literal) {
036                return INTEGER_LITERAL_PATTERN.matcher(literal).matches();
037        }
038
039        /** Parses the string literal, if it is valid. */
040        public static int parse(String literal) {
041                if (!isInteger(literal)) {
042                        throw new NumberFormatException(literal + " is not a valid C++ integer literal");
043                }
044                int base = 10;
045                if (literal.startsWith("0x") || literal.startsWith("0X")) {
046                        base = 16;
047                        literal = literal.substring(2);
048                } else if (literal.startsWith("0b") || literal.startsWith("0B")) {
049                        base = 2;
050                        literal = literal.substring(2);
051                } else if (literal.startsWith("0")) {
052                        base = 8;
053                }
054                literal = removeInvalidCharacters(literal);
055                return Integer.parseInt(literal, base);
056        }
057
058        private static String removeInvalidCharacters(String literal) {
059                literal = literal.replace("\'", "");
060                literal = literal.replace("u", "");
061                literal = literal.replace("l", "");
062                literal = literal.replace("U", "");
063                literal = literal.replace("L", "");
064                return literal;
065        }
066
067}