Skip to content
Snippets Groups Projects
Commit b53b3dcf authored by Alexander Schultheiß's avatar Alexander Schultheiß
Browse files

Initial template files

parents
Branches
No related merge requests found
/target
/.idea
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "beef"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bed554bd50246729a1ec158d08aa3235d1b69d94ad120ebe187e28894787e736"
[[package]]
name = "cb-2"
version = "0.1.0"
dependencies = [
"logos",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "logos"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "427e2abca5be13136da9afdbf874e6b34ad9001dd70f2b103b083a85daa7b345"
dependencies = [
"logos-derive",
]
[[package]]
name = "logos-derive"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56a7d287fd2ac3f75b11f19a1c8a874a7d55744bd91f7a1b3e7cf87d4343c36d"
dependencies = [
"beef",
"fnv",
"proc-macro2",
"quote",
"regex-syntax",
"syn",
"utf8-ranges",
]
[[package]]
name = "proc-macro2"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "syn"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "unicode-xid"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
[[package]]
name = "utf8-ranges"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba"
[package]
name = "cb-2"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
logos = "0.12.0"
# Übungsblatt 2
## Generelles
Diese beiden Aufgaben dienen dem Einstieg in die Zerlegung von Text mit der [logos](https://crates.io/crates/logos) crate.
Sie implementieren die lexikalische Analyse für unseren Praktikumsinterpreter der Sprache C1.
## Allgemeine Hinweise
Für diese und alle folgenden Praktikumsaufgaben gilt, dass Einsendungen, die in der jeweils mitgegebenen Testumgebung nicht laufen, mit null Punkten bewertet werden!
Das beinhaltet insbesondere alle Programme, die sich nicht fehlerfrei kompilieren lassen.
Da Cargo für die Ausführung verantwortlich ist, sollte das Projekt bei Ihnen am Ende mit `cargo test` ohne Fehler und Warnungen durchlaufen.
## Abgabemodus
Die Lösung ist in einem eigenen Git-Repository abzugeben.
Sie können in ihrer Lösung jedoch beliebige Hilfstypen und Module selbst definieren.
Die grundlegende Struktur des hier mitgegebenen Templates sollte jedoch nicht verändert werden.
Zur Lösung der Aufgaben steht für Sie dieses Repository mit
- vorgegebenen Modulen [c1](src/lexer/c1.rs) und [url](src/lexer/url.rs)
- Testfälle (Integrationstests) innerhalb der Dateien [c1_lexer](tests/c1_lexer.rs) und [url_lexer](tests/url_lexer.rs)
zur Verfügung.
> Sie können die Implementierung mit `cargo test` prüfen. Mit `cargo test -- --nocapture` werden Konsolenausgaben auch bei korrekten Tests angezeigt.
## Aufgabe 1 (50 Punkte)
### Kurzbeschreibung
Implementieren Sie mithilfe von [logos](https://crates.io/crates/logos) einen Scanner, der in einem Eingabestrom bzw. in einer Eingabedatei die Token der Sprache C1 erkennt.
### Aufgabenstellung
Mittels logos sollen sie einen Scanner implementieren, der aus einem Eingabestrom die Token der Sprache C1 extrahiert.
Die Lexik der Sprache C1 befindet sich [hier](https://amor.cms.hu-berlin.de/~kunert/lehre/material/c1-lexic.php). Zusätzlich sind folgende Punkte zu beachten:
- die Implementation befindet sich in der Datei [c1](src/lexer/c1.rs)
- Whitespaces (Leerzeichen, Tabulatoren, Zeilenenden) sollen vom Scanner ignoriert werden
- C- (/* */) und C++- (//) Kommentare sollen überlesen werden
- alle nicht in C1 erlaubten Zeichen (etwa "&") sollen zur Rückgabe der `Error` Variante führen
- wenn Sie den Scanner auf das mitgelieferte C1-Beispielprogramm [demorgan.c1](tests/resources/demorgan.c1) ansetzen, sollte `cargo test -- --nocapture` die in [demorgan_tokens](tests/resources/demorgan_tokens.txt) stehende Ausgabe erzeugen
## Aufgabe 2 (50 Punkte)
### Kurzbeschreibung
Implementieren Sie mit Hilfe von [logos](https://crates.io/crates/logos) einen Scanner, der in einem Eingabestrom bzw. aus einer Eingabedatei URLs und damit verbundene Linkbeschreibungen extrahiert.
### Aufgabenstellung
Der zweite zu implementierende Scanner soll mittels logos aus einem Eingabestrom im xhtml-Format die URLs und die Linktexte extrahieren und ausgeben.
Zur Vereinfachung der Analyse gelten folgende Konventionen:
- der Eingabestrom ist valides xhtml, das keinen CDATA Abschnitt enthält. Die Links haben das Format <a ... href="URL" ... >LINKTEXT</a>, wobei im schließenden Tag nach dem 'a' null oder mehr Leerzeichen und Newlines stehen dürfen. Innerhalb des öffnenden Tags dürfen vor und nach href weitere Attribute auftreten, die überlesen werden
- Newlines innerhalb von LINKTEXT gehören zum Linktext. D.h. alles innerhalb des a-Tags gehört zum Linktext
- zwischen <a ...> und </a> treten keine anderen Tags auf
- a-Tags, die kein href-Attribut beinhalten, werden komplett ignoriert
- die Eingabe enthält keinerlei Kommentare
Wenn Sie den Scanner auf [urls.html](tests/resources/urls.html) ansetzen, sollte `cargo test -- --nocapture` die in [url_tokens](tests/resources/url_tokens.txt) stehende Ausgabe erzeugen.
\ No newline at end of file
pub mod c1;
pub mod url;
\ No newline at end of file
use logos::Logos;
#[derive(Logos, Debug, PartialEq)]
pub enum C1Token {
// TODO: Define variants and their token/regex
// Logos requires one token variant to handle errors,
// it can be named anything you wish.
#[error]
Error,
}
use logos::{Lexer, Logos, Source};
use std::fmt::{Display, Formatter};
/// Tuple struct for link URLs
#[derive(Debug, PartialEq)]
pub struct LinkUrl(String);
/// Implement Display for printing
impl Display for LinkUrl {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
/// Tuple struct for link texts
#[derive(Debug, PartialEq)]
pub struct LinkText(String);
/// Implement Display for printing
impl Display for LinkText {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
/// Token enum for capturing of link URLs and Texts
#[derive(Logos, Debug, PartialEq)]
pub enum URLToken {
// TODO: Capture link definitions
Link((LinkUrl, LinkText)),
// TODO: Ignore all characters that do not belong to a link definition
Ignored,
// Catch any error
#[error]
Error,
}
/// Extracts the URL and text from a string that matched a Link token
fn extract_link_info(lex: &mut Lexer<URLToken>) -> (LinkUrl, LinkText) {
// TODO: Implement extraction from link definition
todo!()
}
pub mod lexer;
use cb_2::lexer::c1::C1Token;
use logos::Logos;
use std::error::Error;
use std::fs;
#[test]
fn scan_demorgan() -> Result<(), Box<dyn Error>> {
let demorgan_input = fs::read_to_string("tests/resources/demorgan.c1")?;
let demorgan_expected = fs::read_to_string("tests/resources/demorgan_tokens.txt")?;
let mut lexer = C1Token::lexer(demorgan_input.as_str());
// Parse all tokens
let mut tokens = Vec::new();
while let Some(val) = lexer.next() {
let parse_result = format!("{:?}: {:?}", val, lexer.slice());
println!("{}", parse_result);
tokens.push(parse_result);
}
for (parsed, expected) in tokens.iter().zip(demorgan_expected.lines()) {
assert_eq!(parsed, expected);
}
Ok(())
}
/* Ueberprueft deMorgans Law */
// Die erwartete Ausgabe steht am Ende dieser Datei
bool not(bool b) {
if (b == true) return false;
else return true;
}
bool morgan11(bool a, bool b) {
return not(a || b);
}
bool morgan12(bool a, bool b) {
return not(a) && not(b);
}
bool morgan21(bool a, bool b) {
return not(a && b);
}
bool morgan22(bool a, bool b) {
return not(a) || not(b);
}
void main() {
bool a = true;
bool b = true;
int i=0;
printf("Testing deMorgans Law");
do {
do {
printf(i);
printf(morgan11(a,b));
printf(morgan12(a,b));
printf(morgan21(a,b));
printf(morgan22(a,b));
i = i+1;
b = not(b);
} while (b != true);
a = not(a);
} while(a != true);
}
/* Erwartete Ausgabe:
0
false
false
false
false
1
false
false
true
true
2
false
false
true
true
3
true
true
true
true
*/
KwBoolean: "bool"
Id: "not"
LParen: "("
KwBoolean: "bool"
Id: "b"
RParen: ")"
LBrace: "{"
KwIf: "if"
LParen: "("
Id: "b"
Eq: "=="
Id: "true"
RParen: ")"
KwReturn: "return"
ConstBoolean: " false"
Semicolon: ";"
KwElse: "else"
KwReturn: "return"
Id: "true"
Semicolon: ";"
RBrace: "}"
KwBoolean: "bool"
Id: "morgan11"
LParen: "("
KwBoolean: "bool"
Id: "a"
Comma: ","
KwBoolean: "bool"
Id: "b"
RParen: ")"
LBrace: "{"
KwReturn: "return"
Id: "not"
LParen: "("
Id: "a"
Or: "||"
Id: "b"
RParen: ")"
Semicolon: ";"
RBrace: "}"
KwBoolean: "bool"
Id: "morgan12"
LParen: "("
KwBoolean: "bool"
Id: "a"
Comma: ","
KwBoolean: "bool"
Id: "b"
RParen: ")"
LBrace: "{"
KwReturn: "return"
Id: "not"
LParen: "("
Id: "a"
RParen: ")"
And: "&&"
Id: "not"
LParen: "("
Id: "b"
RParen: ")"
Semicolon: ";"
RBrace: "}"
KwBoolean: "bool"
Id: "morgan21"
LParen: "("
KwBoolean: "bool"
Id: "a"
Comma: ","
KwBoolean: "bool"
Id: "b"
RParen: ")"
LBrace: "{"
KwReturn: "return"
Id: "not"
LParen: "("
Id: "a"
And: "&&"
Id: "b"
RParen: ")"
Semicolon: ";"
RBrace: "}"
KwBoolean: "bool"
Id: "morgan22"
LParen: "("
KwBoolean: "bool"
Id: "a"
Comma: ","
KwBoolean: "bool"
Id: "b"
RParen: ")"
LBrace: "{"
KwReturn: "return"
Id: "not"
LParen: "("
Id: "a"
RParen: ")"
Or: "||"
Id: "not"
LParen: "("
Id: "b"
RParen: ")"
Semicolon: ";"
RBrace: "}"
KwVoid: "void"
Id: "main"
LParen: "("
RParen: ")"
LBrace: "{"
KwBoolean: "bool"
Id: "a"
Assign: "="
Id: "true"
Semicolon: ";"
KwBoolean: "bool"
Id: "b"
Assign: "="
Id: "true"
Semicolon: ";"
KwInt: "int"
Id: "i"
Assign: "="
ConstInt: "0"
Semicolon: ";"
KwPrintf: "printf"
LParen: "("
ConstString: "\"Testing deMorgans Law\""
RParen: ")"
Semicolon: ";"
KwDo: "do"
LBrace: "{"
KwDo: "do"
LBrace: "{"
KwPrintf: "printf"
LParen: "("
Id: "i"
RParen: ")"
Semicolon: ";"
KwPrintf: "printf"
LParen: "("
Id: "morgan11"
LParen: "("
Id: "a"
Comma: ","
Id: "b"
RParen: ")"
RParen: ")"
Semicolon: ";"
KwPrintf: "printf"
LParen: "("
Id: "morgan12"
LParen: "("
Id: "a"
Comma: ","
Id: "b"
RParen: ")"
RParen: ")"
Semicolon: ";"
KwPrintf: "printf"
LParen: "("
Id: "morgan21"
LParen: "("
Id: "a"
Comma: ","
Id: "b"
RParen: ")"
RParen: ")"
Semicolon: ";"
KwPrintf: "printf"
LParen: "("
Id: "morgan22"
LParen: "("
Id: "a"
Comma: ","
Id: "b"
RParen: ")"
RParen: ")"
Semicolon: ";"
Id: "i"
Assign: "="
Id: "i"
Plus: "+"
ConstInt: "1"
Semicolon: ";"
Id: "b"
Assign: "="
Id: "not"
LParen: "("
Id: "b"
RParen: ")"
Semicolon: ";"
RBrace: "}"
KwWhile: "while"
LParen: "("
Id: "b"
Neq: "!="
Id: "true"
RParen: ")"
Semicolon: ";"
Id: "a"
Assign: "="
Id: "not"
LParen: "("
Id: "a"
RParen: ")"
Semicolon: ";"
RBrace: "}"
KwWhile: "while"
LParen: "("
Id: "a"
Neq: "!="
Id: "true"
RParen: ")"
Semicolon: ";"
RBrace: "}"
\ No newline at end of file
LinkUrl("http://www2.informatik.hu-berlin.de/sam"): LinkText("Lehrstuhlseiten - sollten ausgegeben werden.")
LinkUrl("http://www.userfriendly.org"): LinkText("Userfriendly - sollte jeder Informatiker kennen (und daher sollte dieser Text auch ausgegeben werden :-)")
\ No newline at end of file
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Aufgabe 4</title>
</head>
<body>
<h1><a name="Ueberschrift">Praktische Informatik III</a></h1>
<p>Zu ignorierender text am Anfang</p>
<p><a href="http://www2.informatik.hu-berlin.de/sam" name="Werbung">Lehrstuhlseiten - sollten ausgegeben werden.</a
></p>
<p>Zu ignorierender Text in der Mitte</p>
<p><a name="Keine URL sondern nur einfacher Anker">Dieser Text soll ignoriert werden, da der Anker keine URL enthält</a ></p>
<p>Zu ignorierender Text in der Mitte</p>
<p><a name="Grundwissen" href="http://www.userfriendly.org">Userfriendly - sollte jeder Informatiker kennen (und daher sollte dieser Text auch ausgegeben werden :-)</a ></p>
<p>Zu ignorierender Text am Ende</p>
</body>
</html>
use cb_2::lexer::url::URLToken;
use cb_2::lexer::url::URLToken::Link;
use logos::Logos;
use std::error::Error;
use std::fs;
#[test]
fn url_lexer() -> Result<(), Box<dyn Error>> {
let html_text = fs::read_to_string("tests/resources/urls.html")?;
let expected_tokens = fs::read_to_string("tests/resources/url_tokens.txt")?;
let mut lexer = URLToken::lexer(html_text.as_str());
// Parse all tokens
let mut tokens = Vec::new();
while let Some(Link((url, text))) = lexer.next() {
let parse_result = format!("{:?}: {:?}", url, text);
println!("{:?}: {:?}", url, text);
tokens.push(parse_result);
}
for (parsed, expected) in tokens.iter().zip(expected_tokens.lines()) {
assert_eq!(parsed, expected);
}
Ok(())
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment