Amélioration du parser Bakefile : gestion des espaces et des commentaires dans les dépendances, commandes et variables

This commit is contained in:
Yanis HAMOUDI 2025-02-08 22:35:00 +01:00
parent bfeec38854
commit 87662825fa

@ -6,6 +6,7 @@ import java.nio.file.Paths;
import java.util.*; import java.util.*;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class BakefileParser { public class BakefileParser {
/** /**
@ -17,19 +18,19 @@ public class BakefileParser {
* Regex pour détecter les targets et leurs dépendances. * Regex pour détecter les targets et leurs dépendances.
* Format : "nom : dépendance1 dépendance2" * Format : "nom : dépendance1 dépendance2"
*/ */
private static final Pattern TARGET_PATTERN = Pattern.compile("^(\\S+)\\s*:\\s*(.*)$"); private static final Pattern TARGET_PATTERN = Pattern.compile("^(\\S+)\\s*:\\s*([^#]*?)\\s*(?:#.*)?$");
/** /**
* Regex pour détecter les lignes de commande associées à une target. * Regex pour détecter les lignes de commande associées à une target.
* Format : " gcc -o program program.c" (ligne indentée) * Format : " gcc -o program program.c" (ligne indentée)
*/ */
private static final Pattern COMMAND_PATTERN = Pattern.compile("^\\t(.+)$"); private static final Pattern COMMAND_PATTERN = Pattern.compile("^\\t(.+?)(?:#.*)?$");
/** /**
* Regex pour détecter les définitions de variables. * Regex pour détecter les définitions de variables.
* Format : "FLAGS = -ansi -pedantic" * Format : "FLAGS = -ansi -pedantic"
*/ */
private static final Pattern VARIABLE_PATTERN = Pattern.compile("^(\\w+)\\s*=\\s*(.*)$"); private static final Pattern VARIABLE_PATTERN = Pattern.compile("^(\\w+)\\s*=\\s*([^#]*?)\\s*(?:#.*)?$");
/** /**
* Première cible trouvée dans le fichier Bakefile. * Première cible trouvée dans le fichier Bakefile.
@ -47,6 +48,22 @@ public class BakefileParser {
firstTarget = null; firstTarget = null;
} }
private List<String> splitDependencies(String depStr) {
if (depStr == null || depStr.trim().isEmpty()) {
return new ArrayList<>();
}
// Remplacer les variables avant de split
String resolvedStr = replaceVariables(depStr.trim());
// Split sur un ou plusieurs espaces et filtrer les chaînes vides
return Arrays.stream(resolvedStr.split("\\s+"))
.map(String::trim)
.filter(s -> !s.isEmpty())
.collect(Collectors.toList());
}
public List<Rule> parse() { public List<Rule> parse() {
List<Rule> rules = new ArrayList<>(); List<Rule> rules = new ArrayList<>();
Set<String> phonyTargets = new HashSet<>(); Set<String> phonyTargets = new HashSet<>();
@ -74,31 +91,32 @@ public class BakefileParser {
continue; continue;
} }
if (line.matches("^ +.*$")) { // Détecte les lignes commençant par des espaces if (line.matches("^ +.*$")) {
System.err.println(filename + ":" + lineNumber + ": *** missing separator. Stop."); System.err.println(filename + ":" + lineNumber + ": *** missing separator. Stop.");
System.exit(1); System.exit(1);
} }
if (varMatcher.matches()) { if (varMatcher.matches()) {
variables.put(varMatcher.group(1), varMatcher.group(2)); // Stocke la variable en enlevant les espaces en début et fin
variables.put(varMatcher.group(1), varMatcher.group(2).trim());
} else if (targetMatcher.matches()) { } else if (targetMatcher.matches()) {
if (currentTarget != null) { if (currentTarget != null) {
rules.add(new Rule( rules.add(new Rule(
replaceVariables(currentTarget), replaceVariables(currentTarget.trim()),
replaceVariablesInList(dependencies), splitDependencies(dependencies.stream()
replaceVariablesInList(commands), .collect(Collectors.joining(" "))),
phonyTargets.contains(currentTarget) replaceVariablesInList(commands),
)); phonyTargets.contains(currentTarget.trim())
));
} }
currentTarget = targetMatcher.group(1); currentTarget = targetMatcher.group(1);
String depStr = targetMatcher.group(2).trim(); String depStr = targetMatcher.group(2);
dependencies = depStr.isEmpty() ? new ArrayList<>() : new ArrayList<>(Arrays.asList(depStr.split("\\s+"))); dependencies = splitDependencies(depStr);
if (firstTarget == null) { if (firstTarget == null) {
firstTarget = replaceVariables(currentTarget); firstTarget = replaceVariables(currentTarget.trim());
} }
if (currentTarget.equals("clean")) { if (currentTarget.equals("clean")) {
phonyTargets.add(currentTarget); phonyTargets.add(currentTarget);
@ -106,16 +124,16 @@ public class BakefileParser {
commands = new ArrayList<>(); commands = new ArrayList<>();
} else if (commandMatcher.matches()) { } else if (commandMatcher.matches()) {
commands.add(commandMatcher.group(1)); commands.add(commandMatcher.group(1).trim());
} }
} }
if (currentTarget != null) { if (currentTarget != null) {
rules.add(new Rule( rules.add(new Rule(
replaceVariables(currentTarget), replaceVariables(currentTarget.trim()),
replaceVariablesInList(dependencies), replaceVariablesInList(dependencies),
replaceVariablesInList(commands), replaceVariablesInList(commands),
phonyTargets.contains(currentTarget) phonyTargets.contains(currentTarget.trim())
)); ));
} }
@ -134,14 +152,13 @@ public class BakefileParser {
for (Map.Entry<String, String> entry : variables.entrySet()) { for (Map.Entry<String, String> entry : variables.entrySet()) {
String key = "$(" + entry.getKey() + ")"; String key = "$(" + entry.getKey() + ")";
if (result.contains(key)) { if (result.contains(key)) {
result = result.replace(key, entry.getValue()); result = result.replace(key, entry.getValue().trim());
replaced = true; replaced = true;
} }
} }
} while (replaced); } while (replaced);
return result; return result.trim();
} }
private List<String> replaceVariablesInList(List<String> items) { private List<String> replaceVariablesInList(List<String> items) {
List<String> resolved = new ArrayList<>(); List<String> resolved = new ArrayList<>();