Advertisement
DakshJain

Experiment 3

Mar 4th, 2025
148
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 8.35 KB | Software | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5.  
  6. #define MAX_RULES 20   // Maximum number of grammar rules
  7. #define MAX_LEN 100    // Maximum length for production strings
  8.  
  9. // Structure representing a grammar rule with its left-hand side (non-terminal)
  10. // and an array of right-hand side production strings.
  11. typedef struct {
  12.     char lhs;                          // Non-terminal on the left-hand side
  13.     char rhs[MAX_RULES][MAX_LEN];        // Array of production strings (right-hand sides)
  14.     int rhs_count;                     // Count of productions for this non-terminal
  15. } GrammarRule;
  16.  
  17. // Global array to hold the grammar rules and the total count of rules.
  18. GrammarRule rules[MAX_RULES];
  19. int num_rules = 0;
  20.  
  21. // Function prototypes
  22. void append_unique(char *set, char symbol);
  23. void get_first_set(char symbol, char *first_set);
  24. void get_follow_set(char symbol, char *follow_set);
  25.  
  26. //-------------------------------------------------------------------
  27. // Append a symbol to a set (string) if it's not already present.
  28. // A space is added after the symbol for better readability.
  29. void append_unique(char *set, char symbol) {
  30.     if (!strchr(set, symbol)) {
  31.         int len = strlen(set);
  32.         if (len < MAX_LEN - 2) {
  33.             set[len] = symbol;
  34.             set[len + 1] = ' ';  // Insert a space after the symbol
  35.             set[len + 2] = '\0';
  36.         }
  37.     }
  38. }
  39.  
  40. //-------------------------------------------------------------------
  41. // Recursively computes the FIRST set for a given symbol.
  42. // If the symbol is a terminal, its FIRST set is just itself.
  43. // For non-terminals, the function examines each production to determine the FIRST set.
  44. void get_first_set(char symbol, char *first_set) {
  45.     // Base case: if symbol is a terminal, add it to FIRST set.
  46.     if (!isupper(symbol)) {
  47.         append_unique(first_set, symbol);
  48.         return;
  49.     }
  50.  
  51.     // Iterate through all grammar rules looking for a rule with this non-terminal.
  52.     for (int i = 0; i < num_rules; i++) {
  53.         if (rules[i].lhs == symbol) {
  54.             // Process each production (right-hand side) of the rule.
  55.             for (int j = 0; j < rules[i].rhs_count; j++) {
  56.                 char *production = rules[i].rhs[j];
  57.                 int is_nullable = 1;  // Flag to check if production can derive epsilon
  58.  
  59.                 // Examine symbols in the production from left to right.
  60.                 for (int k = 0; production[k] != '\0' && is_nullable; k++) {
  61.                     char current_symbol = production[k];
  62.                     char temp_set[MAX_LEN] = "";
  63.  
  64.                     // If current symbol is a terminal, add it and break out.
  65.                     if (!isupper(current_symbol)) {
  66.                         append_unique(first_set, current_symbol);
  67.                         is_nullable = 0;
  68.                     } else {
  69.                         // Recursively compute FIRST set for the non-terminal.
  70.                         get_first_set(current_symbol, temp_set);
  71.                         // Add symbols (except epsilon, represented by '#') from temp_set.
  72.                         for (int m = 0; temp_set[m] != '\0'; m += 2) {
  73.                             if (temp_set[m] != '#')
  74.                                 append_unique(first_set, temp_set[m]);
  75.                         }
  76.                         // If epsilon is not present, this production is not nullable.
  77.                         if (!strchr(temp_set, '#'))
  78.                             is_nullable = 0;
  79.                     }
  80.                 }
  81.                 // If the entire production can derive epsilon, add epsilon to FIRST set.
  82.                 if (is_nullable)
  83.                     append_unique(first_set, '#');
  84.             }
  85.         }
  86.     }
  87. }
  88.  
  89. //-------------------------------------------------------------------
  90. // Recursively computes the FOLLOW set for a given non-terminal symbol.
  91. // FOLLOW set contains terminals that can immediately appear after the symbol in a derivation.
  92. void get_follow_set(char symbol, char *follow_set) {
  93.     // If the symbol is the start symbol, add the end marker '$'.
  94.     // printf("Computing FOLLOW(%c)\n", symbol);
  95.     if (symbol == rules[0].lhs) {
  96.         append_unique(follow_set, '$');
  97.     }
  98.  
  99.     // Traverse each rule to locate occurrences of the symbol.
  100.     for (int i = 0; i < num_rules; i++) {
  101.         for (int j = 0; j < rules[i].rhs_count; j++) {
  102.             char *production = rules[i].rhs[j];
  103.             int prod_len = strlen(production);
  104.  
  105.             // Look for the symbol in the production.
  106.             for (int k = 0; k < prod_len; k++) {
  107.                 if (production[k] == symbol) {
  108.                     int is_nullable = 1;  // Assume subsequent symbols can derive epsilon
  109.                     // Process symbols following the found symbol.
  110.                     for (int l = k + 1; l < prod_len && is_nullable; l++) {
  111.                         char next_symbol = production[l];
  112.                         char temp_set[MAX_LEN] = "";
  113.  
  114.                         // If next symbol is a terminal, add it to FOLLOW set.
  115.                         if (!isupper(next_symbol)) {
  116.                             append_unique(follow_set, next_symbol);
  117.                             is_nullable = 0;
  118.                         } else {
  119.                             // Otherwise, compute FIRST set for the non-terminal.
  120.                             get_first_set(next_symbol, temp_set);
  121.                             // Add all terminal symbols from FIRST (excluding epsilon) to FOLLOW.
  122.                             for (int m = 0; temp_set[m] != '\0'; m += 2) {
  123.                                 if (temp_set[m] != '#')
  124.                                     append_unique(follow_set, temp_set[m]);
  125.                             }
  126.                             // If epsilon is not in FIRST, then no further symbols are nullable.
  127.                             if (!strchr(temp_set, '#'))
  128.                                 is_nullable = 0;
  129.                         }
  130.                     }
  131.                     // If the following part is nullable, add FOLLOW of the current rule's LHS.
  132.                     if (is_nullable && rules[i].lhs != symbol) {
  133.                         // printf("Adding FOLLOW(%c) to FOLLOW(%c)\n", rules[i].lhs, symbol);
  134.                         char temp_follow[MAX_LEN] = "";
  135.                         get_follow_set(rules[i].lhs, temp_follow);
  136.                         for (int m = 0; temp_follow[m] != '\0'; m += 2) {
  137.                             append_unique(follow_set, temp_follow[m]);
  138.                         }
  139.                     }
  140.                 }
  141.             }
  142.         }
  143.     }
  144.     // printf("FOLLOW(%c) = { %s }\n", symbol, follow_set);
  145. }
  146.  
  147. //-------------------------------------------------------------------
  148. // Main function: Reads grammar rules, computes FIRST and FOLLOW sets,
  149. // and prints the results in a formatted manner.
  150. int main() {
  151.     char input_line[MAX_LEN];
  152.  
  153.     // Read the number of grammar rules.
  154.     printf("Enter number of rules: ");
  155.     scanf("%d", &num_rules);
  156.     getchar(); // Consume newline
  157.  
  158.     // Input each grammar rule.
  159.     for (int i = 0; i < num_rules; i++) {
  160.         printf("Enter rule : ");
  161.         fgets(input_line, sizeof(input_line), stdin);
  162.         input_line[strcspn(input_line, "\n")] = '\0'; // Remove newline character
  163.  
  164.         // Set the left-hand side (non-terminal) of the rule.
  165.         rules[i].lhs = input_line[0];
  166.         rules[i].rhs_count = 0;
  167.  
  168.         // Tokenize the right-hand side productions separated by '|'.
  169.         char *token = strtok(&input_line[3], "|");
  170.         while (token && rules[i].rhs_count < MAX_RULES) {
  171.             strcpy(rules[i].rhs[rules[i].rhs_count++], token);
  172.             token = strtok(NULL, "|");
  173.         }
  174.     }
  175.  
  176.     // Compute and print FIRST sets for each rule.
  177.     printf("\n--- FIRST SETS ---\n");
  178.     for (int i = 0; i < num_rules; i++) {
  179.         char first_output[MAX_LEN] = "";
  180.         get_first_set(rules[i].lhs, first_output);
  181.         printf("FIRST(%c) = { %s}\n", rules[i].lhs, first_output);
  182.     }
  183.  
  184.     // Compute and print FOLLOW sets for each rule.
  185.     printf("\n--- FOLLOW SETS ---\n");
  186.     for (int i = 0; i < num_rules; i++) {
  187.         char follow_output[MAX_LEN] = "";
  188.         // printf("hi");
  189.         get_follow_set(rules[i].lhs, follow_output);
  190.         printf("FOLLOW(%c) = { %s}\n", rules[i].lhs, follow_output);
  191.     }
  192.  
  193.     return 0;
  194. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement