Skip to content

Done with LS CAT WC PWD #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/main/java/antlr/Bash.g4
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
grammar Bash;

start : pipeline EOF #pipe
| assignment EOF #assign
;

pipeline : command #singleCommand
| left=pipeline (' '*) '|' (' '*) right=command #multipleCommands
;

command : (part(' '*))+
;

part : WORD #partWord
| SQSTR #sqstr
| DQSTR #dqstr
| '$' WORD #partVariable
;

assignment : name=WORD '=' value=WORD #wordAssignment
| name=WORD '=' '$' value=WORD #variableAssignment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Странно, что присваивать можно только WORD и $WORD, а как же строки в кавычках?

;


SQSTR: '\'' .*? '\'';
DQSTR: '"' .*? '"';

WORD : [a-zA-Z0-9-]+;
3 changes: 3 additions & 0 deletions src/main/java/bntler/BashAssignment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package bntler;

public record BashAssignment(String result) implements BashNode {}
6 changes: 6 additions & 0 deletions src/main/java/bntler/BashCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package bntler;

import java.util.List;

public record BashCommand (List<String> parts) implements BashNode {
}
4 changes: 4 additions & 0 deletions src/main/java/bntler/BashNode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package bntler;

public interface BashNode {
}
7 changes: 7 additions & 0 deletions src/main/java/bntler/BashPipeline.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package bntler;

import java.util.List;

public record BashPipeline(BashNode left, BashNode right) implements BashNode{

}
45 changes: 45 additions & 0 deletions src/main/java/bntler/PipelineVisitor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package bntler;

import antlr.BashBaseVisitor;
import antlr.BashLexer;
import antlr.BashParser;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;

import java.util.Objects;

public class PipelineVisitor extends BashBaseVisitor<BashNode> {

WordOrStringVisitor wordOrStringVisitor = new WordOrStringVisitor();

@Override
public BashNode visitPipe(BashParser.PipeContext ctx) {
return visit(ctx.pipeline());
}

@Override
public BashNode visitMultipleCommands(BashParser.MultipleCommandsContext ctx) {
var left = visit(ctx.left);
var right = visit(ctx.right);
return new BashPipeline(left, right);
}

@Override
public BashNode visitSingleCommand(BashParser.SingleCommandContext ctx) {
return visit(ctx.command());
}

@Override
public BashNode visitCommand(BashParser.CommandContext ctx) {
var command = ctx.children.stream()
.map(it -> wordOrStringVisitor.visit(it))
.filter(Objects::nonNull)
.toList();
return new BashCommand(command);
}

@Override
public BashNode visitAssign(BashParser.AssignContext ctx) {
return new BashAssignment(wordOrStringVisitor.visit(ctx.assignment()));
}
}
59 changes: 59 additions & 0 deletions src/main/java/bntler/WordOrStringVisitor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package bntler;

import antlr.BashBaseVisitor;
import antlr.BashParser;
import parser.Environment;

import java.util.Map;

public class WordOrStringVisitor extends BashBaseVisitor<String> {

@Override
public String visitAssign(BashParser.AssignContext ctx) {
visit(ctx.assignment());
return "";
}

@Override
public String visitPartWord(BashParser.PartWordContext ctx) {
return ctx.WORD().toString();
}

@Override
public String visitPartVariable(BashParser.PartVariableContext ctx) {
return Environment.values.get(ctx.WORD().toString());
}

@Override
public String visitVariableAssignment(BashParser.VariableAssignmentContext ctx) {
String newVar = Environment.values.get(ctx.WORD(1).toString());
Environment.values.put(ctx.WORD(0).toString(), newVar);
return "";
}

@Override
public String visitWordAssignment(BashParser.WordAssignmentContext ctx) {
// TODO: 02.06.2022 figure out how to make this smoother
Environment.values.put(ctx.WORD(0).toString(), ctx.WORD(1).toString());
return "";
}

@Override
public String visitDqstr(BashParser.DqstrContext ctx) {
String dqstr = ctx.DQSTR().toString();
String noQuotes = dqstr.substring(1, dqstr.length() - 1);

for (Map.Entry<String, String> entry : Environment.values.entrySet()) {
if (noQuotes.contains("$"+entry.getKey())) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Пробелы вокруг операторов

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Пробелы вокруг операторов

noQuotes = noQuotes.replace("$"+entry.getKey(), entry.getValue());
}
}
return noQuotes;
}

@Override
public String visitSqstr(BashParser.SqstrContext ctx) {
String sqstr = ctx.SQSTR().toString();
return sqstr.substring(1, sqstr.length() - 1);
}
}
19 changes: 7 additions & 12 deletions src/main/java/builtins/Cat.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package builtins;

import bntler.BashCommand;
import parser.Bash;
import parser.Expr;
import parser.Token;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
Expand All @@ -12,11 +11,11 @@
import java.util.List;

public class Cat {
public static String execute1(Expr.Command command, String stdin) {
List<Token> args = command.arguments;
int i = 0;
public static String execute(BashCommand command, String stdin) throws IOException {
List<String> args = command.parts();
int i = 1;
while (i < args.size()) {
if (!args.get(i).literal.startsWith("-")) {
if (!args.get(i).startsWith("-")) {
break;
}
i++;
Expand All @@ -28,12 +27,8 @@ public static String execute1(Expr.Command command, String stdin) {

StringBuilder concatenated = new StringBuilder();
while (i < args.size()) {
try {
Path path = Paths.get(args.get(i).literal);
concatenated.append(Files.readString(path, StandardCharsets.UTF_8));
} catch (IOException e) {
Bash.error("No such file " +args.get(i));
}
Path path = Paths.get(args.get(i));
concatenated.append(Files.readString(path, StandardCharsets.UTF_8));
i++;
}
return concatenated.toString();
Expand Down
28 changes: 9 additions & 19 deletions src/main/java/builtins/Echo.java
Original file line number Diff line number Diff line change
@@ -1,34 +1,24 @@
package builtins;

import bntler.BashCommand;
import org.jetbrains.annotations.Nullable;
import parser.*;

public class Echo {
public static String execute1(Expr.Command command, @Nullable String stdin) {
public static String execute(BashCommand command, @Nullable String stdin) {
StringBuilder echoWhat = new StringBuilder();

int i = 0;
int i = 1;
boolean flag = true;
if (!command.arguments.isEmpty() && command.arguments.get(0).literal.equals("-n")) {
i = 1;
if (!command.parts().isEmpty() && command.parts().get(i).equals("-n")) {
i++;
flag = false;
}

for (; i < command.arguments.size(); i++) {
Token tok = command.arguments.get(i);
if (tok.type == TokenType.SINGLE_S) {
echoWhat.append(tok.literal);
} else if (tok.type == TokenType.DOUBLE_S) {
echoWhat.append(Bash.runExternal(tok.literal));
} else {
if (tok.literal.startsWith("$")) {
String key = tok.literal.substring(1);
echoWhat.append(Interpreter.environment.get(key));
} else {
echoWhat.append(tok.literal);
}
for (; i < command.parts().size(); i++) {
echoWhat.append(command.parts().get(i));
if (i != command.parts().size() - 1) {
echoWhat.append(" ");
}
echoWhat.append(" ");
}

if (flag) {
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/builtins/Pwd.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package builtins;

import parser.Expr;
import bntler.BashCommand;

import java.nio.file.Paths;

public class Pwd {
public static String execute1(Expr.Command command, String stdin) {
return Paths.get(".").toAbsolutePath().normalize().toString();
public static String execute(BashCommand command, String stdin) {
return Paths.get(".").toAbsolutePath().normalize().toString() + "\n";
}
}
27 changes: 13 additions & 14 deletions src/main/java/builtins/Wc.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package builtins;

import bntler.BashCommand;
import parser.Bash;
import parser.Expr;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
Expand All @@ -11,31 +11,30 @@
import java.util.regex.Pattern;

public class Wc {
public static String execute1(Expr.Command command, String stdin) {
if (!command.arguments.isEmpty()) {
try {
Path path = Paths.get(command.arguments.get(0).literal);
String content = Files.readString(path, StandardCharsets.US_ASCII);
return wcInner(content);
} catch (IOException e) {
Bash.error("no such file");
return "";
}
public static String execute(BashCommand command, String stdin) throws IOException {
if (command.parts().size() > 1) {
Path path = Paths.get(command.parts().get(1));
String content = Files.readString(path, StandardCharsets.US_ASCII);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Крайне плохая идея -- считывать весь файл целиком в строку

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Крайне плохая идея -- считывать весь файл целиком в строку

return wcInner(content, path.getFileName().toString());
} else if (stdin != null) {
return wcInner(stdin);
return wcInner(stdin, "");
} else {
throw new IllegalStateException("Not Implemented");
}
}

private static String wcInner(String input) {
private static String wcInner(String input, String path) {

final Pattern nonWordPattern = Pattern.compile("\\W");
long charCount = input.lines().flatMapToInt(String::chars).count();
long lineCount = input.lines().count();
long wordCount = input.lines()
.flatMap(nonWordPattern::splitAsStream)
.filter(str -> !str.isEmpty()).count();
return lineCount + " " + wordCount + " " + charCount + "\n";
if (path.isEmpty()) {
return lineCount + " " + wordCount + " " + charCount + "\n";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String.format?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String.format?

} else {
return lineCount + " " + wordCount + " " + charCount + " " + path + "\n";
}
}
}
53 changes: 22 additions & 31 deletions src/main/java/parser/Bash.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package parser;

import antlr.BashLexer;
import antlr.BashParser;
import bntler.PipelineVisitor;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;

public class Bash {
private static final Interpreter interpreter = new Interpreter();
static boolean hadError = false;
static boolean hadRuntimeError = false;

public static void main(String[] args) throws IOException {
if (args.length > 1) {
Expand All @@ -25,7 +29,6 @@ private static void runPrompt() throws IOException {
for (;;) {
System.out.print("> ");
run(reader.readLine());
hadError = false;
}
}

Expand All @@ -35,36 +38,24 @@ private static void run(String source) {
}

public static String runExternal(String source) {
Scanner scanner = new Scanner(source);
List<Token> tokens = scanner.scanTokens();
Parser parser = new Parser(tokens);
Expr statements = parser.parse();

// Stop if there was a syntax error.
if (hadError) return "";

return interpreter.interpret(statements);
}

public static void error(String message) {
report("", message);
}

private static void report(String where, String message) {
System.err.println("Error" + where + ": " + message);
hadError = true;
}

public static void error(Token token, String message) {
if (token.type == TokenType.EOF) {
report(" at end", message);
} else {
report(" at '" + token.rawText + "'", message);
if (source.isEmpty()) {
return "\n";
}
}

public static void runtimeError(RuntimeError error) {
System.err.println(error.getMessage());
hadRuntimeError = true;
var input = CharStreams.fromString(source);
var lexer = new BashLexer(input);
var tokens = new CommonTokenStream(lexer);
var parser = new BashParser(tokens);
var rootNode = parser.start();
var rootNodeGood = new PipelineVisitor().visit(rootNode);
String result;
try {
result = interpreter.interpret(rootNodeGood);
} catch (Exception e) {
// e.printStackTrace(); for debug

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не должно быть закомментированного кода

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не должно быть закомментированного кода

result = e + "\n";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А почему игнорируется исключение и тупо stdout пишется?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А почему игнорируется исключение и тупо stdout пишется?

}
return result;
}
}
Loading