<|instruction|>
Solve the below problem. The solution should start with an abridged problem statement. Then key observations. Then full solution based on the observations. Then C++ and Python implementations with comments.

274. Spam-filter
time limit per test: 0.25 sec.
memory limit per test: 65536 KB
input: standard
output: standard



After tremendous last-year success not yet well-known, but already grown-up company H&H decided to create a new software masterpiece -- a world-leading spam-filter.
Due to Your poor last year -- a world-leading spam-filter. Due to your poor last year project performance, you are given a small and boring task again.
Your task is to write a simple email-validator.

Valid email address can be described as follows:
<letter> ::= a|b|...|z|A|B|...|Z

<symbol> ::= <letter>|0|1|...|9|_|-

<word> ::= <symbol>|<symbol><word>

<prefix> ::= <word>|<prefix>.<word>

<domain> ::= <letter><letter>|<letter><letter><letter>

<suffix> ::= <prefix>.<domain>

<address> ::= <prefix>@<suffix>

Input
The first line of the input file contains integer number N (1 <= N <= 100) -- the number of email addresses to be checked. Each of the following N lines contains one email address. Email address is the non-empty sequence of characters with ASCII codes from 32 to 255 no more then 100 characters long.

Output
For each address from the input write a separate line with the word YES, if the email address is valid and NO if it is not.

Sample test(s)

Input
3
abc@abc
abc@abc.abc
_@-.ru

Output
NO
YES
YES
Author:	Ilya V. Elterman
Resource:	ACM ICPC 2004-2005, NEERC, Southern Subregional Contest
Date:	Saratov, October 7, 2004

<|response|>
1. Abridged Problem Statement  
Given N candidate email addresses (1 ≤ N ≤ 100, each up to 100 characters long), determine for each whether it matches the following grammar:

  address ::= prefix '@' suffix  
  prefix  ::= word ('.' word)*  
  word    ::= one or more symbols  
  symbol  ::= letter | digit | '_' | '-'  
  suffix  ::= prefix '.' domain  
  domain  ::= exactly 2 or 3 letters  

Report “YES” if the address is valid, otherwise “NO”.

2. Key Observations  
- There must be exactly one ‘@’ splitting the string into a left part (local prefix) and a right part (suffix).  
- A prefix (on either side of ‘@’ or before the final dot in the suffix)  
  • is non‐empty  
  • does not begin or end with '.'  
  • does not contain consecutive dots (“..”)  
  • contains only symbols or dots, where a symbol is letter, digit, ‘_’ or ‘-’.  
- The suffix must contain at least one dot. Splitting at the last dot gives:  
  • a sub‐prefix (validated by the same prefix rules)  
  • a domain of length 2 or 3 made only of letters.  
- All checks can be done in a single linear pass per string (O(length_of_string)).

3. Full Solution Approach  
For each email string S:  
  1. Check there is exactly one '@'. If not, reject.  
  2. Split into local = S[0..at−1], rest = S[at+1..end].  
  3. Validate local with prefix rules. If invalid, reject.  
  4. In rest, find the last dot. If none, reject.  
  5. Split rest into mid = rest[0..dot−1], dom = rest[dot+1..end].  
  6. Validate mid with prefix rules. If invalid, reject.  
  7. Check dom length is 2 or 3 and all characters are letters. If not, reject.  
  8. If all checks pass, accept; otherwise reject.  

4. C++ Implementation with Detailed Comments  
```cpp
#include <bits/stdc++.h>
using namespace std;

// Check if a character is a valid “symbol”: letter, digit, '_' or '-'
bool is_symbol(char ch) {
    return isalpha(static_cast<unsigned char>(ch))
        || isdigit(static_cast<unsigned char>(ch))
        || ch == '_' || ch == '-';
}

// Validate a prefix string according to the rules:
// - non-empty
// - does not start or end with '.'
// - no consecutive dots
// - each non-dot character is a valid symbol
bool is_valid_prefix(const string &s) {
    if (s.empty()) return false;
    if (s.front() == '.' || s.back() == '.') return false;
    bool last_was_dot = false;
    for (char ch : s) {
        if (ch == '.') {
            if (last_was_dot) return false;  // consecutive dots
            last_was_dot = true;
        } else {
            if (!is_symbol(ch)) return false;
            last_was_dot = false;
        }
    }
    return true;
}

// Validate that domain is exactly 2 or 3 letters
bool is_valid_domain(const string &d) {
    if (d.size() != 2 && d.size() != 3) return false;
    for (char ch : d) {
        if (!isalpha(static_cast<unsigned char>(ch)))
            return false;
    }
    return true;
}

// Validate the full suffix: it must be prefix + '.' + domain
bool is_valid_suffix(const string &suffix) {
    // find last dot
    size_t pos = suffix.rfind('.');
    if (pos == string::npos) return false;
    string mid = suffix.substr(0, pos);
    string dom = suffix.substr(pos + 1);
    return is_valid_prefix(mid) && is_valid_domain(dom);
}

// Validate the entire email: prefix + '@' + suffix
bool is_valid_email(const string &email) {
    // find the '@'; ensure exactly one
    size_t first_at = email.find('@');
    if (first_at == string::npos) return false;
    if (email.find('@', first_at + 1) != string::npos) return false;
    string local = email.substr(0, first_at);
    string rest  = email.substr(first_at + 1);
    return is_valid_prefix(local) && is_valid_suffix(rest);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N;
    cin >> N;
    cin.ignore(numeric_limits<streamsize>::max(), '\n');
    string line;
    for (int i = 0; i < N; i++) {
        getline(cin, line);
        cout << (is_valid_email(line) ? "YES" : "NO") << "\n";
    }
    return 0;
}
```

5. Python Implementation with Detailed Comments  
```python
import sys

def is_symbol(ch):
    # Letters, digits, underscore or hyphen
    return ch.isalpha() or ch.isdigit() or ch in '_-'

def is_valid_prefix(pref):
    # Must be non-empty
    if not pref:
        return False
    # Cannot start or end with dot
    if pref[0] == '.' or pref[-1] == '.':
        return False
    last_dot = False
    for ch in pref:
        if ch == '.':
            # No consecutive dots
            if last_dot:
                return False
            last_dot = True
        else:
            # Every non-dot must be a symbol
            if not is_symbol(ch):
                return False
            last_dot = False
    return True

def is_valid_domain(dom):
    # Exactly 2 or 3 letters
    return len(dom) in (2, 3) and all(ch.isalpha() for ch in dom)

def is_valid_suffix(suf):
    # Must contain at least one dot
    i = suf.rfind('.')
    if i == -1:
        return False
    mid, dom = suf[:i], suf[i+1:]
    return is_valid_prefix(mid) and is_valid_domain(dom)

def is_valid_email(email):
    # Must contain exactly one '@'
    if email.count('@') != 1:
        return False
    i = email.find('@')
    local, rest = email[:i], email[i+1:]
    return is_valid_prefix(local) and is_valid_suffix(rest)

def main():
    data = sys.stdin.read().splitlines()
    n = int(data[0])
    for email in data[1:1+n]:
        print("YES" if is_valid_email(email) else "NO")

if __name__ == "__main__":
    main()
```

Explanation of Steps in Code:  
- We first split at the single ‘@’ to isolate the local‐part and the suffix.  
- `is_valid_prefix` enforces the word‐and‐dot rules for both the local part and the prefix of the suffix.  
- `is_valid_suffix` splits at the last dot to extract the domain, then validates both sub‐prefix and domain.  
- The domain is checked for exact length (2 or 3) and letters only.  
- If every check passes, we output “YES”; otherwise, “NO”.