def p_create_pair(p): "create_list : STRING COMMA multi_type" if check_layer_name(p[1]) == False: print_error("Error: layer name unknown, you can use only: APP or NET or MAC", str(p.lineno(1))) p[0] = str(p[1]) + ":" + str(p[3])
def p_statement_assign(p): """ statement : ID EQUALS expression | ID PLUSEQ expression | ID MINUSEQ expression | ID TIMESEQ expression | ID DIVIDEQ expression | ID MODULEQ expression """ # check if the ID is already declared and if it is a variable if str(p[1]) not in symbol_table.keys(): print_error("Error: '" + str(p[1]) + "' is not declared", str(p.lineno(1))) else: if symbol_table[str(p[1])] != 'VAR': print_error("Error: '" + str(p[1]) + "' is not a variable", str(p.lineno(1))) expression = str(p[3]) expression += "\n\t\t\t\t<item>" + str(p[2]) + "</item>" expression += "\n\t\t\t\t<item>" + str(p[1]) + "</item>" action = Expression(expression) actions.append(action)
def p_full_path(p): "full_path : STRING" full_path = str(p[1]) # Remove char '"' full_path = full_path.replace("\"", "") # Check the consistency of the full path of fields "layer.field1.field2.field3 ..." id_counter = 0 while len(full_path) != 0: # Search identifier in the string head try: substring_found = re.search('^[a-zA-Z_][a-zA-Z_0-9]*', full_path).group(0) id_counter += 1 except AttributeError: print_error( "Error: layer.field attribute in the packet-filter has a bad structure, layer or field name is missing", str(p.lineno(1))) # Check if the layer is valid if id_counter == 1: if substring_found not in (layer_names): if substring_found not in (control_structures_names): print_error( "Error: layer name unknown, you can use only APP or TRA or NET or MAC or control structures", str(p.lineno(1))) # Remove substring found full_path = full_path.replace(substring_found, "", 1) if len(full_path) == 0: break # Search '.' in the string head try: substring_found = re.search('^\.', full_path).group(0) except AttributeError: print_error( "Error: layer.field attribute in packet-filter has a bad structure, '.' is missing", str(p.lineno(1))) full_path = full_path.replace(substring_found, "", 1) if len(full_path) == 0: print_error( "Error: layer.field attribute in change action has a bad structure, field name is missing", str(p.lineno(1))) if id_counter < 2: print_error( "Error: layer.field attribute in packet-filter has a bad structure, field name is missing", str(p.lineno(1))) # Full path checked p[0] = str(p[1])
def p_function_statement(p): "function_statement : FUNCTION function_id EQUALS function_argument" # Check if the function identifier is already declared if (str(p[2]) in global_symbol_table.keys() or str(p[2]) in symbol_table.keys()): print_error("Error: ID '" + str(p[2]) + "' is already declared ", str(p.lineno(2))) else: # Add the function identifier to the global symbol table global_symbol_table[str(p[2])] = "FUNCTION" functions[str(p[2])] = p[4]
def p_statement_list(p): "list_statement : LIST list_id EQUALS LCBRACKET list_members RCBRACKET" # Check if the list identifier is already declared if (str(p[2]) in global_symbol_table.keys() or str(p[2]) in symbol_table.keys()): print_error("Error: ID '" + str(p[2]) + "' is already declared ", str(p.lineno(2))) else: # Add the list identifier to the global symbol table global_symbol_table[str(p[2])] = "LIST" lists[str(p[2])] = p[5]
def p_expression_id(p): "expression : ID" # Check if the ID is already declared and if it is a variable if str(p[1]) not in symbol_table.keys(): print_error("Error: '" + str(p[1]) + "' is not declared", str(p.lineno(1)) ) else: if symbol_table[str(p[1])] != 'VAR': print_error("Error: '" + str(p[1]) + "' is not a variable", str(p.lineno(1)) ) else: p[0] = "\n\t\t\t\t<item>" + str(p[1]) + "</item>"
def p_statement_packetdef(p): "statement : PACKET ID" if str(p[2]) == "original": print_error("Error: '" + str(p[2]) + "' is a reserved name", str(p.lineno(1))) # Check if this identifier has been already declared for this attack if str(p[2]) in symbol_table.keys(): print_error("Error: '" + str(p[2]) + "' is already declared", str(p.lineno(1))) else : # Add the identifier to the symbol table if str(p[2]) != "original": symbol_table[str(p[2])] = "PACKET"
def p_expression_id(p): "expression : ID" # Check if the ID is already declared and if it is a variable if str(p[1]) not in symbol_table.keys(): print_error("Error: '" + str(p[1]) + "' is not declared", str(p.lineno(1))) else: if symbol_table[str(p[1])] != 'VAR': print_error("Error: '" + str(p[1]) + "' is not a variable", str(p.lineno(1))) else: p[0] = "\n\t\t\t\t<item>" + str(p[1]) + "</item>"
def p_statement_retrieve(p): "logical_statement : RETRIEVE LPAREN identifier COMMA layer_field_pair COMMA identifier RPAREN" if p[3] != "original": packet_check(p[3], p.lineno(1)) # Check if the variable is reserved if p[7] in reserved_name: print_error("Error: '" + p[7] + "' is a reserved name", str(p.lineno(1)) ) # Check if the variable has been previously declared if p[7] not in symbol_table.keys(): print_error("Error: '" + p[7] + "' undefined variable identifier", str(p.lineno(1)) ) # Check if the name has been previously used to declare a packet if p[7] in symbol_table.keys() and symbol_table[p[7]] != "VAR": print_error("Error: ID overloading is not allowed", str(p.lineno(1)) ) # Check if the layer name is valid if check_layer_name(p[5]) == False: print_error("Error: layer name unknown, you can use only: APP or NET or MAC", str(p.lineno(1))) args = str(p[3]) + ":" + str(p[5]) + ":" + str(p[7]) action = Retrieve(args) actions.append(action)
def p_statement_vardef(p): "statement : VAR ID" # Check if the name is a reserved one (e.g. RANDOM) if str(p[2]) in reserved_name: print_error("Error : '" + str(p[2]) + "' is a reserved name", str(p.lineno(2)) ) # Check if this identifier has been already declared for this attack elif str(p[2]) in symbol_table.keys(): print_error("Error : '" + str(p[2]) + "' is already declared", str(p.lineno(2)) ) else: # Add the identifier to the symbol and variable table (the type is NONE) symbol_table[str(p[2])] = "VAR" variables[str(p[2])] = "<value></value><type>NONE</type>"
def p_statement_varinit(p): "statement : VAR ID EQUALS init" # Check if the name is a reserved one (e.g. RANDOM) if str(p[2]) in reserved_name: print_error("Error: '" + str(p[2]) + "' is a reserved name", str(p.lineno(2))) # Check if this identifier has been already declared for the current attack elif str(p[2]) in symbol_table.keys(): print_error("Error : '" + str(p[2]) + "' is already declared", str(p.lineno(2))) else: # Add the identifier to the symbol and variable table symbol_table[str(p[2])] = "VAR" variables[str(p[2])] = str(p[4])
def p_conditional_attack(p): "conditional_attack : FROM time NODES IN list_id DO LCBRACKET filter_codeblock RCBRACKET" # Check if the node list has been declared if str(p[5]) not in lists.keys(): print_error("Error: list '" + str(p[5]) + "' is not declared", str(p.lineno(5))) # Replace | with : node_list = lists[p[5]].replace("|", ":") # Build the attack and add it to the conditional attack list attack = ConditionalAttack(p[2], node_list, variables, actions, p[8]) conditional_attacks.append(attack) # Clear data structures for the next attack clear_data_structure()
def p_statement_packetdef(p): "statement : PACKET ID" if str(p[2]) == "original": print_error("Error: '" + str(p[2]) + "' is a reserved name", str(p.lineno(1))) # Check if this identifier has been already declared for this attack if str(p[2]) in symbol_table.keys(): print_error("Error: '" + str(p[2]) + "' is already declared", str(p.lineno(1))) else: # Add the identifier to the symbol table if str(p[2]) != "original": symbol_table[str(p[2])] = "PACKET"
def p_statement_put(p): "logical_statement : PUT LPAREN identifier COMMA identifier COMMA direction COMMA boolean COMMA unsigned_real RPAREN" if p[3] != "original": packet_check(p[3], p.lineno(1)) # Check if the list has been already declared if p[5] not in lists.keys(): print_error("Error: list '" + p[5] + "' is not declared", str(p.lineno(1)) ) # Replace the second argument with the list content p[5] = str(lists[str(p[5])]) args = str(p[3]) + ":" + str(p[5]) + ":" + str(p[7]) + ":" + str(p[9]) + ":" + str(p[11]) action = Put(args) actions.append(action)
def p_statement_vardef(p): "statement : VAR ID" # Check if the name is a reserved one (e.g. RANDOM) if str(p[2]) in reserved_name: print_error("Error : '" + str(p[2]) + "' is a reserved name", str(p.lineno(2))) # Check if this identifier has been already declared for this attack elif str(p[2]) in symbol_table.keys(): print_error("Error : '" + str(p[2]) + "' is already declared", str(p.lineno(2))) else: # Add the identifier to the symbol and variable table (the type is NONE) symbol_table[str(p[2])] = "VAR" variables[str(p[2])] = "<value></value><type>NONE</type>"
def p_full_path(p): "full_path : STRING" full_path = str(p[1]) # Remove char '"' full_path = full_path.replace("\"", "") # Check the consistency of the full path of fields "layer.field1.field2.field3 ..." id_counter = 0 while len(full_path) != 0: # Search identifier in the string head try: substring_found = re.search('^[a-zA-Z_][a-zA-Z_0-9]*', full_path).group(0) id_counter += 1 except AttributeError: print_error("Error: layer.field attribute in the packet-filter has a bad structure, layer or field name is missing", str(p.lineno(1))) # Check if the layer is valid if id_counter == 1: if substring_found not in (layer_names): if substring_found not in (control_structures_names): print_error("Error: layer name unknown, you can use only APP or TRA or NET or MAC or control structures", str(p.lineno(1))) # Remove substring found full_path = full_path.replace(substring_found, "", 1) if len(full_path) == 0: break; # Search '.' in the string head try: substring_found = re.search('^\.', full_path).group(0) except AttributeError: print_error("Error: layer.field attribute in packet-filter has a bad structure, '.' is missing", str(p.lineno(1))) full_path = full_path.replace(substring_found, "", 1) if len(full_path) == 0: print_error("Error: layer.field attribute in change action has a bad structure, field name is missing", str(p.lineno(1))) if id_counter < 2: print_error("Error: layer.field attribute in packet-filter has a bad structure, field name is missing", str(p.lineno(1))) # Full path checked p[0] = str(p[1])
def p_statement_fakeread(p): "physical_statement : FAKEREAD LPAREN node_id COMMA time COMMA sensor_id COMMA identifier RPAREN" # Check if the function has been already declared if p[9] not in functions.keys(): print_error("Error: function '" + p[9] + "' is not declared", str(p.lineno(1)) ) # Replace the identifier with its content p[9] = str(functions[str(p[9])]) fakeread_args = "" + str(p[7]) + ":" + str(p[9]) if not p[5] in fakeread_actions.keys(): fakeread_actions[p[5]] = {} if not fakeread_args in fakeread_actions[p[5]].keys(): fakeread_actions[p[5]][fakeread_args] = "" + str(p[3]) else: fakeread_actions[p[5]][fakeread_args] = fakeread_actions[p[5]][fakeread_args] + ":" + str(p[3])
def p_statement_fakeread(p): "physical_statement : FAKEREAD LPAREN node_id COMMA time COMMA sensor_id COMMA identifier RPAREN" # Check if the function has been already declared if p[9] not in functions.keys(): print_error("Error: function '" + p[9] + "' is not declared", str(p.lineno(1))) # Replace the identifier with its content p[9] = str(functions[str(p[9])]) fakeread_args = "" + str(p[7]) + ":" + str(p[9]) if not p[5] in fakeread_actions.keys(): fakeread_actions[p[5]] = {} if not fakeread_args in fakeread_actions[p[5]].keys(): fakeread_actions[p[5]][fakeread_args] = "" + str(p[3]) else: fakeread_actions[p[5]][fakeread_args] = fakeread_actions[ p[5]][fakeread_args] + ":" + str(p[3])
def p_statement_assign(p): """ statement : ID EQUALS expression | ID PLUSEQ expression | ID MINUSEQ expression | ID TIMESEQ expression | ID DIVIDEQ expression | ID MODULEQ expression """ # check if the ID is already declared and if it is a variable if str(p[1]) not in symbol_table.keys(): print_error("Error: '" + str(p[1]) + "' is not declared", str(p.lineno(1)) ) else: if symbol_table[str(p[1])] != 'VAR': print_error("Error: '"+str(p[1])+"' is not a variable", str(p.lineno(1)) ) expression = str(p[3]) expression += "\n\t\t\t\t<item>" + str(p[2]) + "</item>" expression += "\n\t\t\t\t<item>" + str(p[1]) + "</item>" action = Expression(expression) actions.append(action)
def p_generic_operand_string(p): """ generic_operand : STRING """ # Remove char '"' operand = (str(p[1]).replace("\"", "")) # Check if operand is a simple string or a local list if re.search('\|', operand): local_list = operand # Check the consistency of the local list id_counter = 0 while len(local_list) != 0: # Search number in the string head try: substring_found = re.search('^\-?\d+(\.\d+)?', local_list).group(0) id_counter += 1 except AttributeError: print_error( "Error: packet-filter's local list supports only list of double", str(p.lineno(1))) # Remove substring found local_list = local_list.replace(substring_found, "", 1) if len(local_list) == 0: break # Search '|' in the string head try: substring_found = re.search('^\|', local_list).group(0) except AttributeError: print_error( "Error: local list's elements in the packet-filter must be separated by the char '|'", str(p.lineno(1))) local_list = local_list.replace(substring_found, "", 1) if len(local_list) == 0: print_error( "Error: missing double in the packet-filter's local list", str(p.lineno(1))) # operand checked p[0] = operand
def p_statement_change(p): "logical_statement : CHANGE LPAREN identifier COMMA layer_field_pair COMMA multi_type RPAREN" # Check the third argument if p[3] != "original": packet_check(p[3], p.lineno(1)) # p[7] is multi_type (NUMBER, STRING, ID) if p[7] not in reserved_name and p[7] not in symbol_table.keys(): re_pattern = r"^-?\d+(\.\d+)?" pattern = re.compile(re_pattern) # Add an entry in the variable table if STRING is not present in it if p[7][0] == "\"" and p[7][-1] == "\"": symbol_table[p[7]] = "VAR" variables[p[7]] = "<value>" + p[7][1:-1] + "</value><type>STRING</type>" # Add an entry in the variable table if NUMBER is not present in it elif re.match(pattern, p[7]): symbol_table[p[7]] = "VAR" variables[p[7]] = "<value>" + p[7] + "</value><type>NUMBER</type>" # Return error if the ID is not declared else: print_error("Error: '" + p[7] + "' undefined variable identifier", str(p.lineno(1)) ) # Check if the variable is initialized if p[7] not in reserved_name: value = variables[p[7]][7] # Variable not initialized if its first char is '<' if value == "<": print_error("Error: variable '" + p[7] + "' must be initialized", str(p.lineno(1)) ) # Check layer name if check_layer_name(p[5]) == False: print_error("Error: layer name unknown, you can use only: APP or NET or MAC", str(p.lineno(1))) args = str(p[3]) + ":" + str(p[5]) + ":" + str(p[7]) action = Change(args) actions.append(action)
def p_generic_operand_string(p): """ generic_operand : STRING """ # Remove char '"' operand = (str(p[1]).replace("\"", "")) # Check if operand is a simple string or a local list if re.search('\|', operand): local_list = operand # Check the consistency of the local list id_counter = 0 while len(local_list) != 0: # Search number in the string head try: substring_found = re.search('^\-?\d+(\.\d+)?', local_list).group(0) id_counter += 1 except AttributeError: print_error("Error: packet-filter's local list supports only list of double", str(p.lineno(1))) # Remove substring found local_list = local_list.replace(substring_found, "", 1) if len(local_list) == 0: break; # Search '|' in the string head try: substring_found = re.search('^\|', local_list).group(0) except AttributeError: print_error("Error: local list's elements in the packet-filter must be separated by the char '|'", str(p.lineno(1))) local_list = local_list.replace(substring_found, "", 1) if len(local_list) == 0: print_error("Error: missing double in the packet-filter's local list", str(p.lineno(1))) # operand checked p[0] = operand
def p_statement_retrieve(p): "logical_statement : RETRIEVE LPAREN identifier COMMA layer_field_pair COMMA identifier RPAREN" if p[3] != "original": packet_check(p[3], p.lineno(1)) # Check if the variable is reserved if p[7] in reserved_name: print_error("Error: '" + p[7] + "' is a reserved name", str(p.lineno(1)) ) # Check if the variable has been previously declared if p[7] not in symbol_table.keys(): print_error("Error: '" + p[7] + "' undefined variable identifier", str(p.lineno(1)) ) # Check if the name has been previously used to declare a packet if p[7] in symbol_table.keys() and symbol_table[p[7]] != "VAR": print_error("Error: ID overloading is not allowed", str(p.lineno(1)) ) # Check if the layer name is valid if check_layer_name(p[5]) == False: print_error("Error: layer name unknown, you can use only: APP or NET or MAC", str(p.lineno(1))) # Check coerency of layer_field structure "layer.field1.field2.field3 ..." layer_field = str(p[5]) id_counter = 0 while len(layer_field) != 0: # search identifier in the string head try: substring_found = re.search('^[a-zA-Z_][a-zA-Z_0-9]*', layer_field).group(0) id_counter += 1 except AttributeError: print_error("Error: layer.field attribute in retrieve action has a bad structure, id missing", str(p.lineno(1))) # remove substring found layer_field = layer_field.replace(substring_found, "", 1) if len(layer_field) == 0: break; # search '.' in the string head try: substring_found = re.search('^\.', layer_field).group(0) except AttributeError: print_error("Error: layer.field attribute in retrieve action has a bad structure, '.' missing", str(p.lineno(1))) layer_field = layer_field.replace(substring_found, "", 1) if len(layer_field) == 0: print_error("Error: layer.field attribute in retrieve action has a bad structure, id missing", str(p.lineno(1))) if id_counter < 2: print_error("Error: layer.field attribute in retrieve action has a bad structure, field missing", str(p.lineno(1))) # Coerency test passed, build the object args = str(p[3]) + ":" + str(p[5]) + ":" + str(p[7]) action = Retrieve(args) actions.append(action)
def p_statement_change(p): "logical_statement : CHANGE LPAREN identifier COMMA layer_field_pair COMMA multi_type RPAREN" # Check the third argument if p[3] != "original": packet_check(p[3], p.lineno(1)) # p[7] is multi_type (NUMBER, STRING, ID) if p[7] not in reserved_name and p[7] not in symbol_table.keys(): re_pattern = r"^-?\d+(\.\d+)?" pattern = re.compile(re_pattern) # Add an entry in the variable table if STRING is not present in it if p[7][0] == "\"" and p[7][-1] == "\"": symbol_table[p[7]] = "VAR" variables[p[7]] = "<value>" + p[7][1:-1] + "</value><type>STRING</type>" # Add an entry in the variable table if NUMBER is not present in it elif re.match(pattern, p[7]): symbol_table[p[7]] = "VAR" variables[p[7]] = "<value>" + p[7] + "</value><type>NUMBER</type>" # Return error if the ID is not declared else: print_error("Error: '" + p[7] + "' undefined variable identifier", str(p.lineno(1)) ) # Check if the variable is initialized if p[7] not in reserved_name: value = variables[p[7]][7] # Variable not initialized if its first char is '<' if value == "<": print_error("Error: variable '" + p[7] + "' must be initialized", str(p.lineno(1)) ) # Check layer name if check_layer_name(p[5]) == False: print_error("Error: layer name unknown, you can use only: APP or NET or MAC", str(p.lineno(1))) # Check coerency of layer_field structure "layer.field1.field2.field3 ..." layer_field = str(p[5]) id_counter = 0 while len(layer_field) != 0: # search identifier in the string head try: substring_found = re.search('^[a-zA-Z_][a-zA-Z_0-9]*', layer_field).group(0) id_counter += 1 except AttributeError: print_error("Error: layer.field attribute in change action has a bad structure, id missing", str(p.lineno(1))) # remove substring found layer_field = layer_field.replace(substring_found, "", 1) if len(layer_field) == 0: break; # search '.' in the string head try: substring_found = re.search('^\.', layer_field).group(0) except AttributeError: print_error("Error: layer.field attribute in change action has a bad structure, '.' missing", str(p.lineno(1))) layer_field = layer_field.replace(substring_found, "", 1) if len(layer_field) == 0: print_error("Error: layer.field attribute in change action has a bad structure, id missing", str(p.lineno(1))) if id_counter < 2: print_error("Error: layer.field attribute in change action has a bad structure, field missing", str(p.lineno(1))) # Coerency test passed, build the object args = str(p[3]) + ":" + str(p[5]) + ":" + str(p[7]) action = Change(args) actions.append(action)
def p_statement_retrieve(p): "logical_statement : RETRIEVE LPAREN identifier COMMA layer_field_pair COMMA identifier RPAREN" if p[3] != "original": packet_check(p[3], p.lineno(1)) # Check if the variable is reserved if p[7] in reserved_name: print_error("Error: '" + p[7] + "' is a reserved name", str(p.lineno(1))) # Check if the variable has been previously declared if p[7] not in symbol_table.keys(): print_error("Error: '" + p[7] + "' undefined variable identifier", str(p.lineno(1))) # Check if the name has been previously used to declare a packet if p[7] in symbol_table.keys() and symbol_table[p[7]] != "VAR": print_error("Error: ID overloading is not allowed", str(p.lineno(1))) # Check if the layer name is valid if check_layer_name(p[5]) == False: print_error( "Error: layer name unknown, you can use only: APP or NET or MAC", str(p.lineno(1))) # Check coerency of layer_field structure "layer.field1.field2.field3 ..." layer_field = str(p[5]) id_counter = 0 while len(layer_field) != 0: # search identifier in the string head try: substring_found = re.search('^[a-zA-Z_][a-zA-Z_0-9]*', layer_field).group(0) id_counter += 1 except AttributeError: print_error( "Error: layer.field attribute in retrieve action has a bad structure, id missing", str(p.lineno(1))) # remove substring found layer_field = layer_field.replace(substring_found, "", 1) if len(layer_field) == 0: break # search '.' in the string head try: substring_found = re.search('^\.', layer_field).group(0) except AttributeError: print_error( "Error: layer.field attribute in retrieve action has a bad structure, '.' missing", str(p.lineno(1))) layer_field = layer_field.replace(substring_found, "", 1) if len(layer_field) == 0: print_error( "Error: layer.field attribute in retrieve action has a bad structure, id missing", str(p.lineno(1))) if id_counter < 2: print_error( "Error: layer.field attribute in retrieve action has a bad structure, field missing", str(p.lineno(1))) # Coerency test passed, build the object args = str(p[3]) + ":" + str(p[5]) + ":" + str(p[7]) action = Retrieve(args) actions.append(action)
def p_statement_change(p): "logical_statement : CHANGE LPAREN identifier COMMA layer_field_pair COMMA multi_type RPAREN" # Check the third argument if p[3] != "original": packet_check(p[3], p.lineno(1)) # p[7] is multi_type (NUMBER, STRING, ID) if p[7] not in reserved_name and p[7] not in symbol_table.keys(): re_pattern = r"^-?\d+(\.\d+)?" pattern = re.compile(re_pattern) # Add an entry in the variable table if STRING is not present in it if p[7][0] == "\"" and p[7][-1] == "\"": symbol_table[p[7]] = "VAR" variables[ p[7]] = "<value>" + p[7][1:-1] + "</value><type>STRING</type>" # Add an entry in the variable table if NUMBER is not present in it elif re.match(pattern, p[7]): symbol_table[p[7]] = "VAR" variables[p[7]] = "<value>" + p[7] + "</value><type>NUMBER</type>" # Return error if the ID is not declared else: print_error("Error: '" + p[7] + "' undefined variable identifier", str(p.lineno(1))) # Check if the variable is initialized if p[7] not in reserved_name: value = variables[p[7]][7] # Variable not initialized if its first char is '<' if value == "<": print_error("Error: variable '" + p[7] + "' must be initialized", str(p.lineno(1))) # Check layer name if check_layer_name(p[5]) == False: print_error( "Error: layer name unknown, you can use only: APP or NET or MAC", str(p.lineno(1))) # Check coerency of layer_field structure "layer.field1.field2.field3 ..." layer_field = str(p[5]) id_counter = 0 while len(layer_field) != 0: # search identifier in the string head try: substring_found = re.search('^[a-zA-Z_][a-zA-Z_0-9]*', layer_field).group(0) id_counter += 1 except AttributeError: print_error( "Error: layer.field attribute in change action has a bad structure, id missing", str(p.lineno(1))) # remove substring found layer_field = layer_field.replace(substring_found, "", 1) if len(layer_field) == 0: break # search '.' in the string head try: substring_found = re.search('^\.', layer_field).group(0) except AttributeError: print_error( "Error: layer.field attribute in change action has a bad structure, '.' missing", str(p.lineno(1))) layer_field = layer_field.replace(substring_found, "", 1) if len(layer_field) == 0: print_error( "Error: layer.field attribute in change action has a bad structure, id missing", str(p.lineno(1))) if id_counter < 2: print_error( "Error: layer.field attribute in change action has a bad structure, field missing", str(p.lineno(1))) # Coerency test passed, build the object args = str(p[3]) + ":" + str(p[5]) + ":" + str(p[7]) action = Change(args) actions.append(action)